[SPIR-V] Use a helper class for most if/else branching
Simplifies emission of the blocks themselves (including inserting blocks into the function's block list in the correct order), as well as phi after the branching. Also fixes 64bpp storing with blending in the fragment shader interlock render backend implementation (had a typo that caused the high 32 bits to overwrite the low ones).
This commit is contained in:
parent
3189a0e259
commit
8e7301f4d8
|
@ -13,6 +13,8 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
@ -101,5 +103,105 @@ spv::Id SpirvBuilder::createTriBuiltinCall(spv::Id result_type,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpirvBuilder::IfBuilder::IfBuilder(spv::Id condition, unsigned int control,
|
||||||
|
SpirvBuilder& builder,
|
||||||
|
unsigned int thenWeight,
|
||||||
|
unsigned int elseWeight)
|
||||||
|
: builder(builder),
|
||||||
|
condition(condition),
|
||||||
|
control(control),
|
||||||
|
thenWeight(thenWeight),
|
||||||
|
elseWeight(elseWeight),
|
||||||
|
function(builder.getBuildPoint()->getParent()) {
|
||||||
|
// Make the blocks, but only put the then-block into the function, the
|
||||||
|
// else-block and merge-block will be added later, in order, after earlier
|
||||||
|
// code is emitted.
|
||||||
|
thenBlock = new spv::Block(builder.getUniqueId(), function);
|
||||||
|
elseBlock = nullptr;
|
||||||
|
mergeBlock = new spv::Block(builder.getUniqueId(), function);
|
||||||
|
|
||||||
|
// Save the current block, so that we can add in the flow control split when
|
||||||
|
// makeEndIf is called.
|
||||||
|
headerBlock = builder.getBuildPoint();
|
||||||
|
|
||||||
|
spv::Id headerBlockId = headerBlock->getId();
|
||||||
|
thenPhiParent = headerBlockId;
|
||||||
|
elsePhiParent = headerBlockId;
|
||||||
|
|
||||||
|
function.addBlock(thenBlock);
|
||||||
|
builder.setBuildPoint(thenBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvBuilder::IfBuilder::makeBeginElse(bool branchToMerge) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert_true(currentBranch == Branch::kThen);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (branchToMerge) {
|
||||||
|
// Close out the "then" by having it jump to the mergeBlock.
|
||||||
|
thenPhiParent = builder.getBuildPoint()->getId();
|
||||||
|
builder.createBranch(mergeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the first else block and add it to the function.
|
||||||
|
elseBlock = new spv::Block(builder.getUniqueId(), function);
|
||||||
|
function.addBlock(elseBlock);
|
||||||
|
|
||||||
|
// Start building the else block.
|
||||||
|
builder.setBuildPoint(elseBlock);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
currentBranch = Branch::kElse;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpirvBuilder::IfBuilder::makeEndIf(bool branchToMerge) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert_true(currentBranch == Branch::kThen || currentBranch == Branch::kElse);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (branchToMerge) {
|
||||||
|
// Jump to the merge block.
|
||||||
|
(elseBlock ? elsePhiParent : thenPhiParent) =
|
||||||
|
builder.getBuildPoint()->getId();
|
||||||
|
builder.createBranch(mergeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go back to the headerBlock and make the flow control split.
|
||||||
|
builder.setBuildPoint(headerBlock);
|
||||||
|
builder.createSelectionMerge(mergeBlock, control);
|
||||||
|
{
|
||||||
|
spv::Block* falseBlock = elseBlock ? elseBlock : mergeBlock;
|
||||||
|
std::unique_ptr<spv::Instruction> branch =
|
||||||
|
std::make_unique<spv::Instruction>(spv::OpBranchConditional);
|
||||||
|
branch->addIdOperand(condition);
|
||||||
|
branch->addIdOperand(thenBlock->getId());
|
||||||
|
branch->addIdOperand(falseBlock->getId());
|
||||||
|
if (thenWeight || elseWeight) {
|
||||||
|
branch->addImmediateOperand(thenWeight);
|
||||||
|
branch->addImmediateOperand(elseWeight);
|
||||||
|
}
|
||||||
|
builder.getBuildPoint()->addInstruction(std::move(branch));
|
||||||
|
thenBlock->addPredecessor(builder.getBuildPoint());
|
||||||
|
falseBlock->addPredecessor(builder.getBuildPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the merge block to the function.
|
||||||
|
function.addBlock(mergeBlock);
|
||||||
|
builder.setBuildPoint(mergeBlock);
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
currentBranch = Branch::kMerge;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
spv::Id SpirvBuilder::IfBuilder::createMergePhi(spv::Id then_variable,
|
||||||
|
spv::Id else_variable) const {
|
||||||
|
assert_true(builder.getBuildPoint() == mergeBlock);
|
||||||
|
return builder.createQuadOp(spv::OpPhi, builder.getTypeId(then_variable),
|
||||||
|
then_variable, getThenPhiParent(), else_variable,
|
||||||
|
getElsePhiParent());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
#ifndef XENIA_GPU_SPIRV_BUILDER_H_
|
#ifndef XENIA_GPU_SPIRV_BUILDER_H_
|
||||||
#define XENIA_GPU_SPIRV_BUILDER_H_
|
#define XENIA_GPU_SPIRV_BUILDER_H_
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
#include "third_party/glslang/SPIRV/SpvBuilder.h"
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
@ -42,6 +45,60 @@ class SpirvBuilder : public spv::Builder {
|
||||||
spv::Id createTriBuiltinCall(spv::Id result_type, spv::Id builtins,
|
spv::Id createTriBuiltinCall(spv::Id result_type, spv::Id builtins,
|
||||||
int entry_point, spv::Id operand1,
|
int entry_point, spv::Id operand1,
|
||||||
spv::Id operand2, spv::Id operand3);
|
spv::Id operand2, spv::Id operand3);
|
||||||
|
|
||||||
|
// Helper to use for building nested control flow with if-then-else with
|
||||||
|
// additions over SpvBuilder::If.
|
||||||
|
class IfBuilder {
|
||||||
|
public:
|
||||||
|
IfBuilder(spv::Id condition, unsigned int control, SpirvBuilder& builder,
|
||||||
|
unsigned int thenWeight = 0, unsigned int elseWeight = 0);
|
||||||
|
|
||||||
|
~IfBuilder() {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert_true(currentBranch == Branch::kMerge);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void makeBeginElse(bool branchToMerge = true);
|
||||||
|
void makeEndIf(bool branchToMerge = true);
|
||||||
|
|
||||||
|
// If there's no then/else block that branches to the merge block, the phi
|
||||||
|
// parent is the header block - this simplifies then-only usage.
|
||||||
|
spv::Id getThenPhiParent() const { return thenPhiParent; }
|
||||||
|
spv::Id getElsePhiParent() const { return elsePhiParent; }
|
||||||
|
|
||||||
|
spv::Id createMergePhi(spv::Id then_variable, spv::Id else_variable) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Branch {
|
||||||
|
kThen,
|
||||||
|
kElse,
|
||||||
|
kMerge,
|
||||||
|
};
|
||||||
|
|
||||||
|
IfBuilder(const IfBuilder& ifBuilder) = delete;
|
||||||
|
IfBuilder& operator=(const IfBuilder& ifBuilder) = delete;
|
||||||
|
|
||||||
|
SpirvBuilder& builder;
|
||||||
|
spv::Id condition;
|
||||||
|
unsigned int control;
|
||||||
|
unsigned int thenWeight;
|
||||||
|
unsigned int elseWeight;
|
||||||
|
|
||||||
|
spv::Function& function;
|
||||||
|
|
||||||
|
spv::Block* headerBlock;
|
||||||
|
spv::Block* thenBlock;
|
||||||
|
spv::Block* elseBlock;
|
||||||
|
spv::Block* mergeBlock;
|
||||||
|
|
||||||
|
spv::Id thenPhiParent;
|
||||||
|
spv::Id elsePhiParent;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
Branch currentBranch = Branch::kThen;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
|
@ -1272,89 +1272,70 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||||
builder_->makeUintConstant(static_cast<unsigned int>(
|
builder_->makeUintConstant(static_cast<unsigned int>(
|
||||||
kSysFlag_ComputeOrPrimitiveVertexIndexLoad))),
|
kSysFlag_ComputeOrPrimitiveVertexIndexLoad))),
|
||||||
const_uint_0_);
|
const_uint_0_);
|
||||||
spv::Block& block_load_vertex_index_pre = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder load_vertex_index_if(
|
||||||
spv::Block& block_load_vertex_index_start = builder_->makeNewBlock();
|
load_vertex_index, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
spv::Block& block_load_vertex_index_merge = builder_->makeNewBlock();
|
spv::Id loaded_vertex_index;
|
||||||
builder_->createSelectionMerge(&block_load_vertex_index_merge,
|
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
builder_->createConditionalBranch(load_vertex_index,
|
|
||||||
&block_load_vertex_index_start,
|
|
||||||
&block_load_vertex_index_merge);
|
|
||||||
builder_->setBuildPoint(&block_load_vertex_index_start);
|
|
||||||
// Check if the index is 32-bit.
|
|
||||||
spv::Id vertex_index_is_32bit = builder_->createBinOp(
|
|
||||||
spv::OpINotEqual, type_bool_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
|
||||||
builder_->makeUintConstant(static_cast<unsigned int>(
|
|
||||||
kSysFlag_ComputeOrPrimitiveVertexIndexLoad32Bit))),
|
|
||||||
const_uint_0_);
|
|
||||||
// Calculate the vertex index address in the shared memory.
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
id_vector_temp_.push_back(
|
|
||||||
builder_->makeIntConstant(kSystemConstantVertexIndexLoadAddress));
|
|
||||||
spv::Id vertex_index_address = builder_->createBinOp(
|
|
||||||
spv::OpIAdd, type_uint_,
|
|
||||||
builder_->createLoad(
|
|
||||||
builder_->createAccessChain(spv::StorageClassUniform,
|
|
||||||
uniform_system_constants_,
|
|
||||||
id_vector_temp_),
|
|
||||||
spv::NoPrecision),
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpShiftLeftLogical, type_uint_, vertex_index,
|
|
||||||
builder_->createTriOp(spv::OpSelect, type_uint_,
|
|
||||||
vertex_index_is_32bit, const_uint_2,
|
|
||||||
builder_->makeUintConstant(1))));
|
|
||||||
// Load the 32 bits containing the whole vertex index or two 16-bit
|
|
||||||
// vertex indices.
|
|
||||||
// TODO(Triang3l): Bounds checking.
|
|
||||||
spv::Id loaded_vertex_index =
|
|
||||||
LoadUint32FromSharedMemory(builder_->createUnaryOp(
|
|
||||||
spv::OpBitcast, type_int_,
|
|
||||||
builder_->createBinOp(spv::OpShiftRightLogical, type_uint_,
|
|
||||||
vertex_index_address, const_uint_2)));
|
|
||||||
// Extract the 16-bit index from the loaded 32 bits if needed.
|
|
||||||
loaded_vertex_index = builder_->createTriOp(
|
|
||||||
spv::OpSelect, type_uint_, vertex_index_is_32bit,
|
|
||||||
loaded_vertex_index,
|
|
||||||
builder_->createTriOp(
|
|
||||||
spv::OpBitFieldUExtract, type_uint_, loaded_vertex_index,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpShiftLeftLogical, type_uint_,
|
|
||||||
builder_->createBinOp(spv::OpBitwiseAnd, type_uint_,
|
|
||||||
vertex_index_address, const_uint_2),
|
|
||||||
builder_->makeUintConstant(4 - 1)),
|
|
||||||
builder_->makeUintConstant(16)));
|
|
||||||
// Endian-swap the loaded index.
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
id_vector_temp_.push_back(
|
|
||||||
builder_->makeIntConstant(kSystemConstantVertexIndexEndian));
|
|
||||||
loaded_vertex_index = EndianSwap32Uint(
|
|
||||||
loaded_vertex_index,
|
|
||||||
builder_->createLoad(
|
|
||||||
builder_->createAccessChain(spv::StorageClassUniform,
|
|
||||||
uniform_system_constants_,
|
|
||||||
id_vector_temp_),
|
|
||||||
spv::NoPrecision));
|
|
||||||
// Get the actual build point for phi.
|
|
||||||
spv::Block& block_load_vertex_index_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_load_vertex_index_merge);
|
|
||||||
// Select between the loaded index and the original index from Vulkan.
|
|
||||||
builder_->setBuildPoint(&block_load_vertex_index_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> loaded_vertex_index_phi_op =
|
// Check if the index is 32-bit.
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
spv::Id vertex_index_is_32bit = builder_->createBinOp(
|
||||||
type_uint_, spv::OpPhi);
|
spv::OpINotEqual, type_bool_,
|
||||||
loaded_vertex_index_phi_op->addIdOperand(loaded_vertex_index);
|
builder_->createBinOp(
|
||||||
loaded_vertex_index_phi_op->addIdOperand(
|
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||||
block_load_vertex_index_end.getId());
|
builder_->makeUintConstant(static_cast<unsigned int>(
|
||||||
loaded_vertex_index_phi_op->addIdOperand(vertex_index);
|
kSysFlag_ComputeOrPrimitiveVertexIndexLoad32Bit))),
|
||||||
loaded_vertex_index_phi_op->addIdOperand(
|
const_uint_0_);
|
||||||
block_load_vertex_index_pre.getId());
|
// Calculate the vertex index address in the shared memory.
|
||||||
vertex_index = loaded_vertex_index_phi_op->getResultId();
|
id_vector_temp_.clear();
|
||||||
builder_->getBuildPoint()->addInstruction(
|
id_vector_temp_.push_back(
|
||||||
std::move(loaded_vertex_index_phi_op));
|
builder_->makeIntConstant(kSystemConstantVertexIndexLoadAddress));
|
||||||
|
spv::Id vertex_index_address = builder_->createBinOp(
|
||||||
|
spv::OpIAdd, type_uint_,
|
||||||
|
builder_->createLoad(
|
||||||
|
builder_->createAccessChain(spv::StorageClassUniform,
|
||||||
|
uniform_system_constants_,
|
||||||
|
id_vector_temp_),
|
||||||
|
spv::NoPrecision),
|
||||||
|
builder_->createBinOp(
|
||||||
|
spv::OpShiftLeftLogical, type_uint_, vertex_index,
|
||||||
|
builder_->createTriOp(spv::OpSelect, type_uint_,
|
||||||
|
vertex_index_is_32bit, const_uint_2,
|
||||||
|
builder_->makeUintConstant(1))));
|
||||||
|
// Load the 32 bits containing the whole vertex index or two 16-bit
|
||||||
|
// vertex indices.
|
||||||
|
// TODO(Triang3l): Bounds checking.
|
||||||
|
loaded_vertex_index =
|
||||||
|
LoadUint32FromSharedMemory(builder_->createUnaryOp(
|
||||||
|
spv::OpBitcast, type_int_,
|
||||||
|
builder_->createBinOp(spv::OpShiftRightLogical, type_uint_,
|
||||||
|
vertex_index_address, const_uint_2)));
|
||||||
|
// Extract the 16-bit index from the loaded 32 bits if needed.
|
||||||
|
loaded_vertex_index = builder_->createTriOp(
|
||||||
|
spv::OpSelect, type_uint_, vertex_index_is_32bit,
|
||||||
|
loaded_vertex_index,
|
||||||
|
builder_->createTriOp(
|
||||||
|
spv::OpBitFieldUExtract, type_uint_, loaded_vertex_index,
|
||||||
|
builder_->createBinOp(
|
||||||
|
spv::OpShiftLeftLogical, type_uint_,
|
||||||
|
builder_->createBinOp(spv::OpBitwiseAnd, type_uint_,
|
||||||
|
vertex_index_address, const_uint_2),
|
||||||
|
builder_->makeUintConstant(4 - 1)),
|
||||||
|
builder_->makeUintConstant(16)));
|
||||||
|
// Endian-swap the loaded index.
|
||||||
|
id_vector_temp_.clear();
|
||||||
|
id_vector_temp_.push_back(
|
||||||
|
builder_->makeIntConstant(kSystemConstantVertexIndexEndian));
|
||||||
|
loaded_vertex_index = EndianSwap32Uint(
|
||||||
|
loaded_vertex_index,
|
||||||
|
builder_->createLoad(
|
||||||
|
builder_->createAccessChain(spv::StorageClassUniform,
|
||||||
|
uniform_system_constants_,
|
||||||
|
id_vector_temp_),
|
||||||
|
spv::NoPrecision));
|
||||||
}
|
}
|
||||||
|
load_vertex_index_if.makeEndIf();
|
||||||
|
// Select between the loaded index and the original index from Vulkan.
|
||||||
|
vertex_index = load_vertex_index_if.createMergePhi(loaded_vertex_index,
|
||||||
|
vertex_index);
|
||||||
} else {
|
} else {
|
||||||
// TODO(Triang3l): Close line loop primitive.
|
// TODO(Triang3l): Close line loop primitive.
|
||||||
// Load the unswapped index as uint for swapping, or for indirect
|
// Load the unswapped index as uint for swapping, or for indirect
|
||||||
|
@ -1368,53 +1349,35 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||||
builder_->makeUintConstant(
|
builder_->makeUintConstant(
|
||||||
static_cast<unsigned int>(kSysFlag_VertexIndexLoad))),
|
static_cast<unsigned int>(kSysFlag_VertexIndexLoad))),
|
||||||
const_uint_0_);
|
const_uint_0_);
|
||||||
spv::Block& block_load_vertex_index_pre = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder load_vertex_index_if(
|
||||||
spv::Block& block_load_vertex_index_start = builder_->makeNewBlock();
|
load_vertex_index, spv::SelectionControlDontFlattenMask,
|
||||||
spv::Block& block_load_vertex_index_merge = builder_->makeNewBlock();
|
*builder_);
|
||||||
builder_->createSelectionMerge(&block_load_vertex_index_merge,
|
spv::Id loaded_vertex_index;
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
builder_->createConditionalBranch(load_vertex_index,
|
|
||||||
&block_load_vertex_index_start,
|
|
||||||
&block_load_vertex_index_merge);
|
|
||||||
builder_->setBuildPoint(&block_load_vertex_index_start);
|
|
||||||
// Load the 32-bit index.
|
|
||||||
// TODO(Triang3l): Bounds checking.
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
id_vector_temp_.push_back(
|
|
||||||
builder_->makeIntConstant(kSystemConstantVertexIndexLoadAddress));
|
|
||||||
spv::Id loaded_vertex_index =
|
|
||||||
LoadUint32FromSharedMemory(builder_->createUnaryOp(
|
|
||||||
spv::OpBitcast, type_int_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpIAdd, type_uint_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpShiftRightLogical, type_uint_,
|
|
||||||
builder_->createLoad(
|
|
||||||
builder_->createAccessChain(
|
|
||||||
spv::StorageClassUniform,
|
|
||||||
uniform_system_constants_, id_vector_temp_),
|
|
||||||
spv::NoPrecision),
|
|
||||||
builder_->makeUintConstant(2)),
|
|
||||||
vertex_index)));
|
|
||||||
// Get the actual build point for phi.
|
|
||||||
spv::Block& block_load_vertex_index_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_load_vertex_index_merge);
|
|
||||||
// Select between the loaded index and the original index from Vulkan.
|
|
||||||
builder_->setBuildPoint(&block_load_vertex_index_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> loaded_vertex_index_phi_op =
|
// Load the 32-bit index.
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
// TODO(Triang3l): Bounds checking.
|
||||||
type_uint_, spv::OpPhi);
|
id_vector_temp_.clear();
|
||||||
loaded_vertex_index_phi_op->addIdOperand(loaded_vertex_index);
|
id_vector_temp_.push_back(builder_->makeIntConstant(
|
||||||
loaded_vertex_index_phi_op->addIdOperand(
|
kSystemConstantVertexIndexLoadAddress));
|
||||||
block_load_vertex_index_end.getId());
|
loaded_vertex_index =
|
||||||
loaded_vertex_index_phi_op->addIdOperand(vertex_index);
|
LoadUint32FromSharedMemory(builder_->createUnaryOp(
|
||||||
loaded_vertex_index_phi_op->addIdOperand(
|
spv::OpBitcast, type_int_,
|
||||||
block_load_vertex_index_pre.getId());
|
builder_->createBinOp(
|
||||||
vertex_index = loaded_vertex_index_phi_op->getResultId();
|
spv::OpIAdd, type_uint_,
|
||||||
builder_->getBuildPoint()->addInstruction(
|
builder_->createBinOp(
|
||||||
std::move(loaded_vertex_index_phi_op));
|
spv::OpShiftRightLogical, type_uint_,
|
||||||
|
builder_->createLoad(
|
||||||
|
builder_->createAccessChain(
|
||||||
|
spv::StorageClassUniform,
|
||||||
|
uniform_system_constants_, id_vector_temp_),
|
||||||
|
spv::NoPrecision),
|
||||||
|
builder_->makeUintConstant(2)),
|
||||||
|
vertex_index)));
|
||||||
}
|
}
|
||||||
|
load_vertex_index_if.makeEndIf();
|
||||||
|
// Select between the loaded index and the original index from Vulkan.
|
||||||
|
vertex_index = load_vertex_index_if.createMergePhi(
|
||||||
|
loaded_vertex_index, vertex_index);
|
||||||
}
|
}
|
||||||
// Endian-swap the index.
|
// Endian-swap the index.
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
|
@ -2808,40 +2771,25 @@ spv::Id SpirvShaderTranslator::EndianSwap32Uint(spv::Id value, spv::Id endian) {
|
||||||
static_cast<unsigned int>(xenos::Endian::k8in32)));
|
static_cast<unsigned int>(xenos::Endian::k8in32)));
|
||||||
spv::Id is_8in16_or_8in32 =
|
spv::Id is_8in16_or_8in32 =
|
||||||
builder_->createBinOp(spv::OpLogicalOr, type_bool_, is_8in16, is_8in32);
|
builder_->createBinOp(spv::OpLogicalOr, type_bool_, is_8in16, is_8in32);
|
||||||
spv::Block& block_pre_8in16 = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder if_8in16(is_8in16_or_8in32,
|
||||||
assert_false(block_pre_8in16.isTerminated());
|
spv::SelectionControlMaskNone, *builder_);
|
||||||
spv::Block& block_8in16 = builder_->makeNewBlock();
|
spv::Id swapped_8in16;
|
||||||
spv::Block& block_8in16_merge = builder_->makeNewBlock();
|
|
||||||
builder_->createSelectionMerge(&block_8in16_merge,
|
|
||||||
spv::SelectionControlMaskNone);
|
|
||||||
builder_->createConditionalBranch(is_8in16_or_8in32, &block_8in16,
|
|
||||||
&block_8in16_merge);
|
|
||||||
builder_->setBuildPoint(&block_8in16);
|
|
||||||
spv::Id swapped_8in16 = builder_->createBinOp(
|
|
||||||
spv::OpBitwiseOr, type,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpBitwiseAnd, type,
|
|
||||||
builder_->createBinOp(spv::OpShiftRightLogical, type, value,
|
|
||||||
const_uint_8_typed),
|
|
||||||
const_uint_00ff00ff_typed),
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpShiftLeftLogical, type,
|
|
||||||
builder_->createBinOp(spv::OpBitwiseAnd, type, value,
|
|
||||||
const_uint_00ff00ff_typed),
|
|
||||||
const_uint_8_typed));
|
|
||||||
builder_->createBranch(&block_8in16_merge);
|
|
||||||
builder_->setBuildPoint(&block_8in16_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
swapped_8in16 = builder_->createBinOp(
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(), type,
|
spv::OpBitwiseOr, type,
|
||||||
spv::OpPhi);
|
builder_->createBinOp(
|
||||||
phi_op->addIdOperand(swapped_8in16);
|
spv::OpBitwiseAnd, type,
|
||||||
phi_op->addIdOperand(block_8in16.getId());
|
builder_->createBinOp(spv::OpShiftRightLogical, type, value,
|
||||||
phi_op->addIdOperand(value);
|
const_uint_8_typed),
|
||||||
phi_op->addIdOperand(block_pre_8in16.getId());
|
const_uint_00ff00ff_typed),
|
||||||
value = phi_op->getResultId();
|
builder_->createBinOp(
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
spv::OpShiftLeftLogical, type,
|
||||||
|
builder_->createBinOp(spv::OpBitwiseAnd, type, value,
|
||||||
|
const_uint_00ff00ff_typed),
|
||||||
|
const_uint_8_typed));
|
||||||
}
|
}
|
||||||
|
if_8in16.makeEndIf();
|
||||||
|
value = if_8in16.createMergePhi(swapped_8in16, value);
|
||||||
|
|
||||||
// 16-in-32 or another half of 8-in-32 (doing 16-in-32 swap).
|
// 16-in-32 or another half of 8-in-32 (doing 16-in-32 swap).
|
||||||
spv::Id is_16in32 = builder_->createBinOp(
|
spv::Id is_16in32 = builder_->createBinOp(
|
||||||
|
@ -2850,32 +2798,18 @@ spv::Id SpirvShaderTranslator::EndianSwap32Uint(spv::Id value, spv::Id endian) {
|
||||||
static_cast<unsigned int>(xenos::Endian::k16in32)));
|
static_cast<unsigned int>(xenos::Endian::k16in32)));
|
||||||
spv::Id is_8in32_or_16in32 =
|
spv::Id is_8in32_or_16in32 =
|
||||||
builder_->createBinOp(spv::OpLogicalOr, type_bool_, is_8in32, is_16in32);
|
builder_->createBinOp(spv::OpLogicalOr, type_bool_, is_8in32, is_16in32);
|
||||||
spv::Block& block_pre_16in32 = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder if_16in32(is_8in32_or_16in32,
|
||||||
spv::Block& block_16in32 = builder_->makeNewBlock();
|
spv::SelectionControlMaskNone, *builder_);
|
||||||
spv::Block& block_16in32_merge = builder_->makeNewBlock();
|
spv::Id swapped_16in32;
|
||||||
builder_->createSelectionMerge(&block_16in32_merge,
|
|
||||||
spv::SelectionControlMaskNone);
|
|
||||||
builder_->createConditionalBranch(is_8in32_or_16in32, &block_16in32,
|
|
||||||
&block_16in32_merge);
|
|
||||||
builder_->setBuildPoint(&block_16in32);
|
|
||||||
spv::Id swapped_16in32 = builder_->createQuadOp(
|
|
||||||
spv::OpBitFieldInsert, type,
|
|
||||||
builder_->createBinOp(spv::OpShiftRightLogical, type, value,
|
|
||||||
const_uint_16_typed),
|
|
||||||
value, builder_->makeIntConstant(16), builder_->makeIntConstant(16));
|
|
||||||
builder_->createBranch(&block_16in32_merge);
|
|
||||||
builder_->setBuildPoint(&block_16in32_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
swapped_16in32 = builder_->createQuadOp(
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(), type,
|
spv::OpBitFieldInsert, type,
|
||||||
spv::OpPhi);
|
builder_->createBinOp(spv::OpShiftRightLogical, type, value,
|
||||||
phi_op->addIdOperand(swapped_16in32);
|
const_uint_16_typed),
|
||||||
phi_op->addIdOperand(block_16in32.getId());
|
value, builder_->makeIntConstant(16), builder_->makeIntConstant(16));
|
||||||
phi_op->addIdOperand(value);
|
|
||||||
phi_op->addIdOperand(block_pre_16in32.getId());
|
|
||||||
value = phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
|
||||||
}
|
}
|
||||||
|
if_16in32.makeEndIf();
|
||||||
|
value = if_16in32.createMergePhi(swapped_16in32, value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,7 +605,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
void SampleTexture(spv::Builder::TextureParameters& texture_parameters,
|
void SampleTexture(spv::Builder::TextureParameters& texture_parameters,
|
||||||
spv::ImageOperandsMask image_operands_mask,
|
spv::ImageOperandsMask image_operands_mask,
|
||||||
spv::Id image_unsigned, spv::Id image_signed,
|
spv::Id image_unsigned, spv::Id image_signed,
|
||||||
spv::Id sampler, spv::Id is_all_signed,
|
spv::Id sampler, spv::Id is_any_unsigned,
|
||||||
spv::Id is_any_signed, spv::Id& result_unsigned_out,
|
spv::Id is_any_signed, spv::Id& result_unsigned_out,
|
||||||
spv::Id& result_signed_out,
|
spv::Id& result_signed_out,
|
||||||
spv::Id lerp_factor = spv::NoResult,
|
spv::Id lerp_factor = spv::NoResult,
|
||||||
|
|
|
@ -40,30 +40,18 @@ spv::Id SpirvShaderTranslator::ZeroIfAnyOperandIsZero(spv::Id value,
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvShaderTranslator::KillPixel(spv::Id condition) {
|
void SpirvShaderTranslator::KillPixel(spv::Id condition) {
|
||||||
// Same calls as in spv::Builder::If.
|
SpirvBuilder::IfBuilder kill_if(condition, spv::SelectionControlMaskNone,
|
||||||
spv::Function& function = builder_->getBuildPoint()->getParent();
|
*builder_);
|
||||||
spv::Block* kill_block = new spv::Block(builder_->getUniqueId(), function);
|
{
|
||||||
spv::Block* merge_block = new spv::Block(builder_->getUniqueId(), function);
|
if (var_main_kill_pixel_ != spv::NoResult) {
|
||||||
spv::Block& header_block = *builder_->getBuildPoint();
|
builder_->createStore(builder_->makeBoolConstant(true),
|
||||||
|
var_main_kill_pixel_);
|
||||||
function.addBlock(kill_block);
|
}
|
||||||
builder_->setBuildPoint(kill_block);
|
if (features_.demote_to_helper_invocation) {
|
||||||
// Kill without influencing the control flow in the translated shader.
|
builder_->createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
|
||||||
if (var_main_kill_pixel_ != spv::NoResult) {
|
}
|
||||||
builder_->createStore(builder_->makeBoolConstant(true),
|
|
||||||
var_main_kill_pixel_);
|
|
||||||
}
|
}
|
||||||
if (features_.demote_to_helper_invocation) {
|
kill_if.makeEndIf();
|
||||||
builder_->createNoResultOp(spv::OpDemoteToHelperInvocationEXT);
|
|
||||||
}
|
|
||||||
builder_->createBranch(merge_block);
|
|
||||||
|
|
||||||
builder_->setBuildPoint(&header_block);
|
|
||||||
builder_->createSelectionMerge(merge_block, spv::SelectionControlMaskNone);
|
|
||||||
builder_->createConditionalBranch(condition, kill_block, merge_block);
|
|
||||||
|
|
||||||
function.addBlock(merge_block);
|
|
||||||
builder_->setBuildPoint(merge_block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpirvShaderTranslator::ProcessAluInstruction(
|
void SpirvShaderTranslator::ProcessAluInstruction(
|
||||||
|
@ -564,7 +552,7 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
spv::Id ma_z_result[4] = {}, ma_yx_result[4] = {};
|
spv::Id ma_z_result[4] = {}, ma_yx_result[4] = {};
|
||||||
|
|
||||||
// Check if the major axis is Z (abs(z) >= abs(x) && abs(z) >= abs(y)).
|
// Check if the major axis is Z (abs(z) >= abs(x) && abs(z) >= abs(y)).
|
||||||
spv::Builder::If ma_z_if(
|
SpirvBuilder::IfBuilder ma_z_if(
|
||||||
builder_->createBinOp(
|
builder_->createBinOp(
|
||||||
spv::OpLogicalAnd, type_bool_,
|
spv::OpLogicalAnd, type_bool_,
|
||||||
builder_->createBinOp(spv::OpFOrdGreaterThanEqual, type_bool_,
|
builder_->createBinOp(spv::OpFOrdGreaterThanEqual, type_bool_,
|
||||||
|
@ -596,14 +584,13 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spv::Block& ma_z_end_block = *builder_->getBuildPoint();
|
|
||||||
ma_z_if.makeBeginElse();
|
ma_z_if.makeBeginElse();
|
||||||
{
|
{
|
||||||
spv::Id ma_y_result[4] = {}, ma_x_result[4] = {};
|
spv::Id ma_y_result[4] = {}, ma_x_result[4] = {};
|
||||||
|
|
||||||
// The major axis is not Z - create an inner conditional to check if the
|
// The major axis is not Z - create an inner conditional to check if the
|
||||||
// major axis is Y (abs(y) >= abs(x)).
|
// major axis is Y (abs(y) >= abs(x)).
|
||||||
spv::Builder::If ma_y_if(
|
SpirvBuilder::IfBuilder ma_y_if(
|
||||||
builder_->createBinOp(spv::OpFOrdGreaterThanEqual, type_bool_,
|
builder_->createBinOp(spv::OpFOrdGreaterThanEqual, type_bool_,
|
||||||
operand_abs[1], operand_abs[0]),
|
operand_abs[1], operand_abs[0]),
|
||||||
spv::SelectionControlMaskNone, *builder_);
|
spv::SelectionControlMaskNone, *builder_);
|
||||||
|
@ -629,7 +616,6 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spv::Block& ma_y_end_block = *builder_->getBuildPoint();
|
|
||||||
ma_y_if.makeBeginElse();
|
ma_y_if.makeBeginElse();
|
||||||
{
|
{
|
||||||
// The major axis is X.
|
// The major axis is X.
|
||||||
|
@ -654,7 +640,6 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spv::Block& ma_x_end_block = *builder_->getBuildPoint();
|
|
||||||
ma_y_if.makeEndIf();
|
ma_y_if.makeEndIf();
|
||||||
|
|
||||||
// The major axis is Y or X - choose the options of the result from Y
|
// The major axis is Y or X - choose the options of the result from Y
|
||||||
|
@ -663,18 +648,10 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
if (!(used_result_components & (1 << i))) {
|
if (!(used_result_components & (1 << i))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
ma_yx_result[i] =
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
ma_y_if.createMergePhi(ma_y_result[i], ma_x_result[i]);
|
||||||
type_float_, spv::OpPhi);
|
|
||||||
phi_op->addIdOperand(ma_y_result[i]);
|
|
||||||
phi_op->addIdOperand(ma_y_end_block.getId());
|
|
||||||
phi_op->addIdOperand(ma_x_result[i]);
|
|
||||||
phi_op->addIdOperand(ma_x_end_block.getId());
|
|
||||||
ma_yx_result[i] = phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spv::Block& ma_yx_end_block = *builder_->getBuildPoint();
|
|
||||||
ma_z_if.makeEndIf();
|
ma_z_if.makeEndIf();
|
||||||
|
|
||||||
// Choose the result options from Z and YX cases.
|
// Choose the result options from Z and YX cases.
|
||||||
|
@ -683,15 +660,8 @@ spv::Id SpirvShaderTranslator::ProcessVectorAluOperation(
|
||||||
if (!(used_result_components & (1 << i))) {
|
if (!(used_result_components & (1 << i))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
id_vector_temp_.push_back(
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
ma_z_if.createMergePhi(ma_z_result[i], ma_yx_result[i]));
|
||||||
type_float_, spv::OpPhi);
|
|
||||||
phi_op->addIdOperand(ma_z_result[i]);
|
|
||||||
phi_op->addIdOperand(ma_z_end_block.getId());
|
|
||||||
phi_op->addIdOperand(ma_yx_result[i]);
|
|
||||||
phi_op->addIdOperand(ma_yx_end_block.getId());
|
|
||||||
id_vector_temp_.push_back(phi_op->getResultId());
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
|
||||||
}
|
}
|
||||||
assert_true(id_vector_temp_.size() == used_result_component_count);
|
assert_true(id_vector_temp_.size() == used_result_component_count);
|
||||||
if (used_result_components & 0b0100) {
|
if (used_result_components & 0b0100) {
|
||||||
|
@ -1044,10 +1014,9 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation(
|
||||||
spv::OpLogicalAnd, type_bool_, condition,
|
spv::OpLogicalAnd, type_bool_, condition,
|
||||||
builder_->createBinOp(spv::OpFOrdGreaterThan, type_bool_, b,
|
builder_->createBinOp(spv::OpFOrdGreaterThan, type_bool_, b,
|
||||||
const_float_0_));
|
const_float_0_));
|
||||||
spv::Block& pre_multiply_if_block = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder multiply_if(
|
||||||
|
condition, spv::SelectionControlMaskNone, *builder_);
|
||||||
spv::Id product;
|
spv::Id product;
|
||||||
spv::Builder::If multiply_if(condition, spv::SelectionControlMaskNone,
|
|
||||||
*builder_);
|
|
||||||
{
|
{
|
||||||
// Multiplication case.
|
// Multiplication case.
|
||||||
spv::Id a = instr.scalar_operands[0].GetComponent(0) !=
|
spv::Id a = instr.scalar_operands[0].GetComponent(0) !=
|
||||||
|
@ -1061,21 +1030,9 @@ spv::Id SpirvShaderTranslator::ProcessScalarAluOperation(
|
||||||
product = ZeroIfAnyOperandIsZero(
|
product = ZeroIfAnyOperandIsZero(
|
||||||
product, GetAbsoluteOperand(a, instr.scalar_operands[0]), ps_abs);
|
product, GetAbsoluteOperand(a, instr.scalar_operands[0]), ps_abs);
|
||||||
}
|
}
|
||||||
spv::Block& multiply_end_block = *builder_->getBuildPoint();
|
|
||||||
multiply_if.makeEndIf();
|
multiply_if.makeEndIf();
|
||||||
// Merge - choose between the product and -FLT_MAX.
|
// Merge - choose between the product and -FLT_MAX.
|
||||||
{
|
return multiply_if.createMergePhi(product, const_float_max_neg);
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
|
||||||
type_float_, spv::OpPhi);
|
|
||||||
phi_op->addIdOperand(product);
|
|
||||||
phi_op->addIdOperand(multiply_end_block.getId());
|
|
||||||
phi_op->addIdOperand(const_float_max_neg);
|
|
||||||
phi_op->addIdOperand(pre_multiply_if_block.getId());
|
|
||||||
spv::Id phi_result = phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
|
||||||
return phi_result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ucode::AluScalarOpcode::kMaxs:
|
case ucode::AluScalarOpcode::kMaxs:
|
||||||
|
|
|
@ -1145,31 +1145,18 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
z_coordinate_ref = builder_->createNoContractionBinOp(
|
z_coordinate_ref = builder_->createNoContractionBinOp(
|
||||||
spv::OpFAdd, type_float_, z_coordinate_ref, z_offset);
|
spv::OpFAdd, type_float_, z_coordinate_ref, z_offset);
|
||||||
}
|
}
|
||||||
spv::Block& block_dimension_head = *builder_->getBuildPoint();
|
|
||||||
spv::Block& block_dimension_merge = builder_->makeNewBlock();
|
|
||||||
spv::Block& block_dimension_3d = builder_->makeNewBlock();
|
|
||||||
builder_->createSelectionMerge(&block_dimension_merge,
|
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
assert_true(data_is_3d != spv::NoResult);
|
assert_true(data_is_3d != spv::NoResult);
|
||||||
builder_->createConditionalBranch(data_is_3d, &block_dimension_3d,
|
SpirvBuilder::IfBuilder if_data_is_3d(
|
||||||
&block_dimension_merge);
|
data_is_3d, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
builder_->setBuildPoint(&block_dimension_3d);
|
spv::Id z_3d;
|
||||||
assert_true(z_size != spv::NoResult);
|
|
||||||
spv::Id z_3d = builder_->createNoContractionBinOp(
|
|
||||||
spv::OpFDiv, type_float_, z_coordinate_ref, z_size);
|
|
||||||
builder_->createBranch(&block_dimension_merge);
|
|
||||||
builder_->setBuildPoint(&block_dimension_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> z_phi_op =
|
assert_true(z_size != spv::NoResult);
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
z_3d = builder_->createNoContractionBinOp(spv::OpFDiv, type_float_,
|
||||||
type_float_, spv::OpPhi);
|
z_coordinate_ref, z_size);
|
||||||
z_phi_op->addIdOperand(z_3d);
|
|
||||||
z_phi_op->addIdOperand(block_dimension_3d.getId());
|
|
||||||
z_phi_op->addIdOperand(z_coordinate_ref);
|
|
||||||
z_phi_op->addIdOperand(block_dimension_head.getId());
|
|
||||||
z_coordinate_ref = z_phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(z_phi_op));
|
|
||||||
}
|
}
|
||||||
|
if_data_is_3d.makeEndIf();
|
||||||
|
z_coordinate_ref =
|
||||||
|
if_data_is_3d.createMergePhi(z_3d, z_coordinate_ref);
|
||||||
} else {
|
} else {
|
||||||
// Denormalize the Z coordinate for a stacked texture, and apply the
|
// Denormalize the Z coordinate for a stacked texture, and apply the
|
||||||
// offset.
|
// offset.
|
||||||
|
@ -1394,63 +1381,39 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
// OpSampledImage must be in the same block as where its result is used.
|
// OpSampledImage must be in the same block as where its result is used.
|
||||||
if (instr.dimension == xenos::FetchOpDimension::k3DOrStacked) {
|
if (instr.dimension == xenos::FetchOpDimension::k3DOrStacked) {
|
||||||
// Check if the texture is 3D or stacked.
|
// Check if the texture is 3D or stacked.
|
||||||
spv::Block& block_dimension_head = *builder_->getBuildPoint();
|
|
||||||
spv::Block& block_dimension_3d_start = builder_->makeNewBlock();
|
|
||||||
spv::Block& block_dimension_stacked_start = builder_->makeNewBlock();
|
|
||||||
spv::Block& block_dimension_merge = builder_->makeNewBlock();
|
|
||||||
builder_->createSelectionMerge(&block_dimension_merge,
|
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
assert_true(data_is_3d != spv::NoResult);
|
assert_true(data_is_3d != spv::NoResult);
|
||||||
builder_->createConditionalBranch(data_is_3d,
|
SpirvBuilder::IfBuilder if_data_is_3d(
|
||||||
&block_dimension_3d_start,
|
data_is_3d, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
&block_dimension_stacked_start);
|
spv::Id lod_3d;
|
||||||
|
|
||||||
// 3D.
|
|
||||||
builder_->setBuildPoint(&block_dimension_3d_start);
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
for (uint32_t i = 0; i < 3; ++i) {
|
|
||||||
id_vector_temp_.push_back(coordinates[i]);
|
|
||||||
}
|
|
||||||
texture_parameters.coords =
|
|
||||||
builder_->createCompositeConstruct(type_float3_, id_vector_temp_);
|
|
||||||
spv::Id lod_3d = QueryTextureLod(texture_parameters,
|
|
||||||
image_3d_unsigned, image_3d_signed,
|
|
||||||
sampler, swizzled_signs_all_signed);
|
|
||||||
// Get the actual build point for phi.
|
|
||||||
spv::Block& block_dimension_3d_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_dimension_merge);
|
|
||||||
|
|
||||||
// 2D stacked.
|
|
||||||
builder_->setBuildPoint(&block_dimension_stacked_start);
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
for (uint32_t i = 0; i < 2; ++i) {
|
|
||||||
id_vector_temp_.push_back(coordinates[i]);
|
|
||||||
}
|
|
||||||
texture_parameters.coords =
|
|
||||||
builder_->createCompositeConstruct(type_float2_, id_vector_temp_);
|
|
||||||
spv::Id lod_stacked = QueryTextureLod(
|
|
||||||
texture_parameters, image_2d_array_or_cube_unsigned,
|
|
||||||
image_2d_array_or_cube_signed, sampler,
|
|
||||||
swizzled_signs_all_signed);
|
|
||||||
// Get the actual build point for phi.
|
|
||||||
spv::Block& block_dimension_stacked_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_dimension_merge);
|
|
||||||
|
|
||||||
// Choose between the 3D and the stacked result based on the actual
|
|
||||||
// data dimensionality.
|
|
||||||
builder_->setBuildPoint(&block_dimension_merge);
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> dimension_phi_op =
|
// 3D.
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
id_vector_temp_.clear();
|
||||||
type_float_, spv::OpPhi);
|
for (uint32_t i = 0; i < 3; ++i) {
|
||||||
dimension_phi_op->addIdOperand(lod_3d);
|
id_vector_temp_.push_back(coordinates[i]);
|
||||||
dimension_phi_op->addIdOperand(block_dimension_3d_end.getId());
|
}
|
||||||
dimension_phi_op->addIdOperand(lod_stacked);
|
texture_parameters.coords = builder_->createCompositeConstruct(
|
||||||
dimension_phi_op->addIdOperand(block_dimension_stacked_end.getId());
|
type_float3_, id_vector_temp_);
|
||||||
result[0] = dimension_phi_op->getResultId();
|
lod_3d = QueryTextureLod(texture_parameters, image_3d_unsigned,
|
||||||
builder_->getBuildPoint()->addInstruction(
|
image_3d_signed, sampler,
|
||||||
std::move(dimension_phi_op));
|
swizzled_signs_all_signed);
|
||||||
}
|
}
|
||||||
|
if_data_is_3d.makeBeginElse();
|
||||||
|
spv::Id lod_stacked;
|
||||||
|
{
|
||||||
|
// 2D stacked.
|
||||||
|
id_vector_temp_.clear();
|
||||||
|
for (uint32_t i = 0; i < 2; ++i) {
|
||||||
|
id_vector_temp_.push_back(coordinates[i]);
|
||||||
|
}
|
||||||
|
texture_parameters.coords = builder_->createCompositeConstruct(
|
||||||
|
type_float2_, id_vector_temp_);
|
||||||
|
lod_stacked = QueryTextureLod(texture_parameters,
|
||||||
|
image_2d_array_or_cube_unsigned,
|
||||||
|
image_2d_array_or_cube_signed,
|
||||||
|
sampler, swizzled_signs_all_signed);
|
||||||
|
}
|
||||||
|
if_data_is_3d.makeEndIf();
|
||||||
|
result[0] = if_data_is_3d.createMergePhi(lod_3d, lod_stacked);
|
||||||
} else {
|
} else {
|
||||||
uint32_t lod_query_coordinate_component_count =
|
uint32_t lod_query_coordinate_component_count =
|
||||||
instr.dimension == xenos::FetchOpDimension::kCube ? 3 : 2;
|
instr.dimension == xenos::FetchOpDimension::kCube ? 3 : 2;
|
||||||
|
@ -1512,6 +1475,8 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
spv::Id is_any_unsigned = builder_->createUnaryOp(
|
||||||
|
spv::OpLogicalNot, type_bool_, is_all_signed);
|
||||||
|
|
||||||
// Load the fetch constant word 4, needed unconditionally for LOD
|
// Load the fetch constant word 4, needed unconditionally for LOD
|
||||||
// biasing, for result exponent biasing, and conditionally for stacked
|
// biasing, for result exponent biasing, and conditionally for stacked
|
||||||
|
@ -1765,273 +1730,247 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
// component, 2 gradient components, two fetches if the Z axis is
|
// component, 2 gradient components, two fetches if the Z axis is
|
||||||
// linear-filtered).
|
// linear-filtered).
|
||||||
|
|
||||||
spv::Block& block_dimension_head = *builder_->getBuildPoint();
|
|
||||||
spv::Block& block_dimension_3d_start = builder_->makeNewBlock();
|
|
||||||
spv::Block& block_dimension_stacked_start = builder_->makeNewBlock();
|
|
||||||
spv::Block& block_dimension_merge = builder_->makeNewBlock();
|
|
||||||
builder_->createSelectionMerge(&block_dimension_merge,
|
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
assert_true(data_is_3d != spv::NoResult);
|
assert_true(data_is_3d != spv::NoResult);
|
||||||
builder_->createConditionalBranch(data_is_3d,
|
SpirvBuilder::IfBuilder if_data_is_3d(
|
||||||
&block_dimension_3d_start,
|
data_is_3d, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
&block_dimension_stacked_start);
|
|
||||||
|
|
||||||
// 3D.
|
|
||||||
builder_->setBuildPoint(&block_dimension_3d_start);
|
|
||||||
if (use_computed_lod) {
|
|
||||||
texture_parameters.gradX = gradients_h;
|
|
||||||
texture_parameters.gradY = gradients_v;
|
|
||||||
}
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
for (uint32_t i = 0; i < 3; ++i) {
|
|
||||||
id_vector_temp_.push_back(coordinates[i]);
|
|
||||||
}
|
|
||||||
texture_parameters.coords =
|
|
||||||
builder_->createCompositeConstruct(type_float3_, id_vector_temp_);
|
|
||||||
spv::Id sample_result_unsigned_3d, sample_result_signed_3d;
|
spv::Id sample_result_unsigned_3d, sample_result_signed_3d;
|
||||||
SampleTexture(texture_parameters, image_operands_mask,
|
{
|
||||||
image_3d_unsigned, image_3d_signed, sampler,
|
// 3D.
|
||||||
is_all_signed, is_any_signed, sample_result_unsigned_3d,
|
if (use_computed_lod) {
|
||||||
sample_result_signed_3d);
|
texture_parameters.gradX = gradients_h;
|
||||||
// Get the actual build point after the SampleTexture call for phi.
|
texture_parameters.gradY = gradients_v;
|
||||||
spv::Block& block_dimension_3d_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_dimension_merge);
|
|
||||||
|
|
||||||
// 2D stacked.
|
|
||||||
builder_->setBuildPoint(&block_dimension_stacked_start);
|
|
||||||
if (use_computed_lod) {
|
|
||||||
// Extract 2D gradients for stacked textures which are 2D arrays.
|
|
||||||
uint_vector_temp_.clear();
|
|
||||||
uint_vector_temp_.push_back(0);
|
|
||||||
uint_vector_temp_.push_back(1);
|
|
||||||
texture_parameters.gradX = builder_->createRvalueSwizzle(
|
|
||||||
spv::NoPrecision, type_float2_, gradients_h, uint_vector_temp_);
|
|
||||||
texture_parameters.gradY = builder_->createRvalueSwizzle(
|
|
||||||
spv::NoPrecision, type_float2_, gradients_v, uint_vector_temp_);
|
|
||||||
}
|
|
||||||
// Check if linear filtering is needed.
|
|
||||||
bool vol_mag_filter_is_fetch_const =
|
|
||||||
instr.attributes.vol_mag_filter ==
|
|
||||||
xenos::TextureFilter::kUseFetchConst;
|
|
||||||
bool vol_min_filter_is_fetch_const =
|
|
||||||
instr.attributes.vol_min_filter ==
|
|
||||||
xenos::TextureFilter::kUseFetchConst;
|
|
||||||
bool vol_mag_filter_is_linear =
|
|
||||||
instr.attributes.vol_mag_filter == xenos::TextureFilter::kLinear;
|
|
||||||
bool vol_min_filter_is_linear =
|
|
||||||
instr.attributes.vol_min_filter == xenos::TextureFilter::kLinear;
|
|
||||||
spv::Id vol_filter_is_linear = spv::NoResult;
|
|
||||||
if (use_computed_lod &&
|
|
||||||
(vol_mag_filter_is_fetch_const || vol_min_filter_is_fetch_const ||
|
|
||||||
vol_mag_filter_is_linear != vol_min_filter_is_linear)) {
|
|
||||||
// Check if minifying along layers (derivative > 1 along any axis).
|
|
||||||
spv::Id layer_max_gradient = builder_->createBinBuiltinCall(
|
|
||||||
type_float_, ext_inst_glsl_std_450_, GLSLstd450NMax,
|
|
||||||
builder_->createCompositeExtract(gradients_h, type_float_, 2),
|
|
||||||
builder_->createCompositeExtract(gradients_v, type_float_, 2));
|
|
||||||
if (!instr.attributes.unnormalized_coordinates) {
|
|
||||||
// Denormalize the gradient if provided as normalized.
|
|
||||||
assert_true(size[2] != spv::NoResult);
|
|
||||||
layer_max_gradient = builder_->createNoContractionBinOp(
|
|
||||||
spv::OpFMul, type_float_, layer_max_gradient, size[2]);
|
|
||||||
}
|
}
|
||||||
// For NaN, considering that magnification is being done.
|
id_vector_temp_.clear();
|
||||||
spv::Id is_minifying_z = builder_->createBinOp(
|
for (uint32_t i = 0; i < 3; ++i) {
|
||||||
spv::OpFOrdLessThan, type_bool_, layer_max_gradient,
|
id_vector_temp_.push_back(coordinates[i]);
|
||||||
builder_->makeFloatConstant(1.0f));
|
|
||||||
// Choose what filter is actually used, the minification or the
|
|
||||||
// magnification one.
|
|
||||||
spv::Id vol_mag_filter_is_linear_loaded =
|
|
||||||
vol_mag_filter_is_fetch_const
|
|
||||||
? builder_->createBinOp(
|
|
||||||
spv::OpINotEqual, type_bool_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpBitwiseAnd, type_uint_,
|
|
||||||
fetch_constant_word_4,
|
|
||||||
builder_->makeUintConstant(UINT32_C(1) << 0)),
|
|
||||||
const_uint_0_)
|
|
||||||
: builder_->makeBoolConstant(vol_mag_filter_is_linear);
|
|
||||||
spv::Id vol_min_filter_is_linear_loaded =
|
|
||||||
vol_min_filter_is_fetch_const
|
|
||||||
? builder_->createBinOp(
|
|
||||||
spv::OpINotEqual, type_bool_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpBitwiseAnd, type_uint_,
|
|
||||||
fetch_constant_word_4,
|
|
||||||
builder_->makeUintConstant(UINT32_C(1) << 1)),
|
|
||||||
const_uint_0_)
|
|
||||||
: builder_->makeBoolConstant(vol_min_filter_is_linear);
|
|
||||||
vol_filter_is_linear =
|
|
||||||
builder_->createTriOp(spv::OpSelect, type_bool_, is_minifying_z,
|
|
||||||
vol_min_filter_is_linear_loaded,
|
|
||||||
vol_mag_filter_is_linear_loaded);
|
|
||||||
} else {
|
|
||||||
// No gradients, or using the same filter overrides for magnifying
|
|
||||||
// and minifying. Assume always magnifying if no gradients (LOD 0,
|
|
||||||
// always <= 0). LOD is within 2D layers, not between them (unlike
|
|
||||||
// in 3D textures, which have mips with depth reduced), so it
|
|
||||||
// shouldn't have effect on filtering between layers.
|
|
||||||
if (vol_mag_filter_is_fetch_const) {
|
|
||||||
vol_filter_is_linear = builder_->createBinOp(
|
|
||||||
spv::OpINotEqual, type_bool_,
|
|
||||||
builder_->createBinOp(
|
|
||||||
spv::OpBitwiseAnd, type_uint_, fetch_constant_word_4,
|
|
||||||
builder_->makeUintConstant(UINT32_C(1) << 0)),
|
|
||||||
const_uint_0_);
|
|
||||||
}
|
}
|
||||||
|
texture_parameters.coords = builder_->createCompositeConstruct(
|
||||||
|
type_float3_, id_vector_temp_);
|
||||||
|
SampleTexture(texture_parameters, image_operands_mask,
|
||||||
|
image_3d_unsigned, image_3d_signed, sampler,
|
||||||
|
is_any_unsigned, is_any_signed,
|
||||||
|
sample_result_unsigned_3d, sample_result_signed_3d);
|
||||||
}
|
}
|
||||||
spv::Id layer_coordinate = coordinates[2];
|
if_data_is_3d.makeBeginElse();
|
||||||
// Linear filtering may be needed either based on a dynamic condition
|
|
||||||
// (the filtering mode is taken from the fetch constant, or it's
|
|
||||||
// different for magnification and minification), or on a static one
|
|
||||||
// (with gradients - specified in the instruction for both
|
|
||||||
// magnification and minification as linear, without gradients -
|
|
||||||
// specified for magnification as linear).
|
|
||||||
// If the filter is linear, subtract 0.5 from the Z coordinate of the
|
|
||||||
// first layer in filtering because 0.5 is in the middle of it.
|
|
||||||
if (vol_filter_is_linear != spv::NoResult) {
|
|
||||||
layer_coordinate = builder_->createTriOp(
|
|
||||||
spv::OpSelect, type_float_, vol_filter_is_linear,
|
|
||||||
builder_->createNoContractionBinOp(
|
|
||||||
spv::OpFSub, type_float_, layer_coordinate,
|
|
||||||
builder_->makeFloatConstant(0.5f)),
|
|
||||||
layer_coordinate);
|
|
||||||
} else if (vol_mag_filter_is_linear) {
|
|
||||||
layer_coordinate = builder_->createNoContractionBinOp(
|
|
||||||
spv::OpFSub, type_float_, layer_coordinate,
|
|
||||||
builder_->makeFloatConstant(0.5f));
|
|
||||||
}
|
|
||||||
// Sample the first layer, needed regardless of whether filtering is
|
|
||||||
// needed.
|
|
||||||
// Floor the array layer (Vulkan does rounding to nearest or + 0.5 and
|
|
||||||
// floor even for the layer index, but on the Xenos, addressing is
|
|
||||||
// similar to that of 3D textures). This is needed for both point and
|
|
||||||
// linear filtering (with linear, 0.5 was subtracted previously).
|
|
||||||
spv::Id layer_0_coordinate = builder_->createUnaryBuiltinCall(
|
|
||||||
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor,
|
|
||||||
layer_coordinate);
|
|
||||||
id_vector_temp_.clear();
|
|
||||||
id_vector_temp_.push_back(coordinates[0]);
|
|
||||||
id_vector_temp_.push_back(coordinates[1]);
|
|
||||||
id_vector_temp_.push_back(layer_0_coordinate);
|
|
||||||
texture_parameters.coords =
|
|
||||||
builder_->createCompositeConstruct(type_float3_, id_vector_temp_);
|
|
||||||
spv::Id sample_result_unsigned_stacked, sample_result_signed_stacked;
|
spv::Id sample_result_unsigned_stacked, sample_result_signed_stacked;
|
||||||
SampleTexture(texture_parameters, image_operands_mask,
|
{
|
||||||
image_2d_array_or_cube_unsigned,
|
// 2D stacked.
|
||||||
image_2d_array_or_cube_signed, sampler, is_all_signed,
|
if (use_computed_lod) {
|
||||||
is_any_signed, sample_result_unsigned_stacked,
|
// Extract 2D gradients for stacked textures which are 2D arrays.
|
||||||
sample_result_signed_stacked);
|
uint_vector_temp_.clear();
|
||||||
// Sample the second layer if linear filtering is potentially needed
|
uint_vector_temp_.push_back(0);
|
||||||
// (conditionally or unconditionally, depending on whether the filter
|
uint_vector_temp_.push_back(1);
|
||||||
// needs to be chosen at runtime), and filter.
|
texture_parameters.gradX =
|
||||||
if (vol_filter_is_linear != spv::NoResult ||
|
builder_->createRvalueSwizzle(spv::NoPrecision, type_float2_,
|
||||||
vol_mag_filter_is_linear) {
|
gradients_h, uint_vector_temp_);
|
||||||
spv::Block& block_z_head = *builder_->getBuildPoint();
|
texture_parameters.gradY =
|
||||||
spv::Block& block_z_linear = (vol_filter_is_linear != spv::NoResult)
|
builder_->createRvalueSwizzle(spv::NoPrecision, type_float2_,
|
||||||
? builder_->makeNewBlock()
|
gradients_v, uint_vector_temp_);
|
||||||
: block_z_head;
|
|
||||||
spv::Block& block_z_merge = (vol_filter_is_linear != spv::NoResult)
|
|
||||||
? builder_->makeNewBlock()
|
|
||||||
: block_z_head;
|
|
||||||
if (vol_filter_is_linear != spv::NoResult) {
|
|
||||||
builder_->createSelectionMerge(
|
|
||||||
&block_z_merge, spv::SelectionControlDontFlattenMask);
|
|
||||||
builder_->createConditionalBranch(
|
|
||||||
vol_filter_is_linear, &block_z_linear, &block_z_merge);
|
|
||||||
builder_->setBuildPoint(&block_z_linear);
|
|
||||||
}
|
}
|
||||||
spv::Id layer_1_coordinate = builder_->createBinOp(
|
// Check if linear filtering is needed.
|
||||||
spv::OpFAdd, type_float_, layer_0_coordinate,
|
bool vol_mag_filter_is_fetch_const =
|
||||||
builder_->makeFloatConstant(1.0f));
|
instr.attributes.vol_mag_filter ==
|
||||||
|
xenos::TextureFilter::kUseFetchConst;
|
||||||
|
bool vol_min_filter_is_fetch_const =
|
||||||
|
instr.attributes.vol_min_filter ==
|
||||||
|
xenos::TextureFilter::kUseFetchConst;
|
||||||
|
bool vol_mag_filter_is_linear = instr.attributes.vol_mag_filter ==
|
||||||
|
xenos::TextureFilter::kLinear;
|
||||||
|
bool vol_min_filter_is_linear = instr.attributes.vol_min_filter ==
|
||||||
|
xenos::TextureFilter::kLinear;
|
||||||
|
spv::Id vol_filter_is_linear = spv::NoResult;
|
||||||
|
if (use_computed_lod &&
|
||||||
|
(vol_mag_filter_is_fetch_const ||
|
||||||
|
vol_min_filter_is_fetch_const ||
|
||||||
|
vol_mag_filter_is_linear != vol_min_filter_is_linear)) {
|
||||||
|
// Check if minifying along layers (derivative > 1 along any
|
||||||
|
// axis).
|
||||||
|
spv::Id layer_max_gradient = builder_->createBinBuiltinCall(
|
||||||
|
type_float_, ext_inst_glsl_std_450_, GLSLstd450NMax,
|
||||||
|
builder_->createCompositeExtract(gradients_h, type_float_, 2),
|
||||||
|
builder_->createCompositeExtract(gradients_v, type_float_,
|
||||||
|
2));
|
||||||
|
if (!instr.attributes.unnormalized_coordinates) {
|
||||||
|
// Denormalize the gradient if provided as normalized.
|
||||||
|
assert_true(size[2] != spv::NoResult);
|
||||||
|
layer_max_gradient = builder_->createNoContractionBinOp(
|
||||||
|
spv::OpFMul, type_float_, layer_max_gradient, size[2]);
|
||||||
|
}
|
||||||
|
// For NaN, considering that magnification is being done.
|
||||||
|
spv::Id is_minifying_z = builder_->createBinOp(
|
||||||
|
spv::OpFOrdLessThan, type_bool_, layer_max_gradient,
|
||||||
|
builder_->makeFloatConstant(1.0f));
|
||||||
|
// Choose what filter is actually used, the minification or the
|
||||||
|
// magnification one.
|
||||||
|
spv::Id vol_mag_filter_is_linear_loaded =
|
||||||
|
vol_mag_filter_is_fetch_const
|
||||||
|
? builder_->createBinOp(
|
||||||
|
spv::OpINotEqual, type_bool_,
|
||||||
|
builder_->createBinOp(
|
||||||
|
spv::OpBitwiseAnd, type_uint_,
|
||||||
|
fetch_constant_word_4,
|
||||||
|
builder_->makeUintConstant(UINT32_C(1) << 0)),
|
||||||
|
const_uint_0_)
|
||||||
|
: builder_->makeBoolConstant(vol_mag_filter_is_linear);
|
||||||
|
spv::Id vol_min_filter_is_linear_loaded =
|
||||||
|
vol_min_filter_is_fetch_const
|
||||||
|
? builder_->createBinOp(
|
||||||
|
spv::OpINotEqual, type_bool_,
|
||||||
|
builder_->createBinOp(
|
||||||
|
spv::OpBitwiseAnd, type_uint_,
|
||||||
|
fetch_constant_word_4,
|
||||||
|
builder_->makeUintConstant(UINT32_C(1) << 1)),
|
||||||
|
const_uint_0_)
|
||||||
|
: builder_->makeBoolConstant(vol_min_filter_is_linear);
|
||||||
|
vol_filter_is_linear = builder_->createTriOp(
|
||||||
|
spv::OpSelect, type_bool_, is_minifying_z,
|
||||||
|
vol_min_filter_is_linear_loaded,
|
||||||
|
vol_mag_filter_is_linear_loaded);
|
||||||
|
} else {
|
||||||
|
// No gradients, or using the same filter overrides for magnifying
|
||||||
|
// and minifying. Assume always magnifying if no gradients (LOD 0,
|
||||||
|
// always <= 0). LOD is within 2D layers, not between them (unlike
|
||||||
|
// in 3D textures, which have mips with depth reduced), so it
|
||||||
|
// shouldn't have effect on filtering between layers.
|
||||||
|
if (vol_mag_filter_is_fetch_const) {
|
||||||
|
vol_filter_is_linear = builder_->createBinOp(
|
||||||
|
spv::OpINotEqual, type_bool_,
|
||||||
|
builder_->createBinOp(
|
||||||
|
spv::OpBitwiseAnd, type_uint_, fetch_constant_word_4,
|
||||||
|
builder_->makeUintConstant(UINT32_C(1) << 0)),
|
||||||
|
const_uint_0_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spv::Id layer_coordinate = coordinates[2];
|
||||||
|
// Linear filtering may be needed either based on a dynamic
|
||||||
|
// condition (the filtering mode is taken from the fetch constant,
|
||||||
|
// or it's different for magnification and minification), or on a
|
||||||
|
// static one (with gradients - specified in the instruction for
|
||||||
|
// both magnification and minification as linear, without
|
||||||
|
// gradients - specified for magnification as linear).
|
||||||
|
// If the filter is linear, subtract 0.5 from the Z coordinate of
|
||||||
|
// the first layer in filtering because 0.5 is in the middle of it.
|
||||||
|
if (vol_filter_is_linear != spv::NoResult) {
|
||||||
|
layer_coordinate = builder_->createTriOp(
|
||||||
|
spv::OpSelect, type_float_, vol_filter_is_linear,
|
||||||
|
builder_->createNoContractionBinOp(
|
||||||
|
spv::OpFSub, type_float_, layer_coordinate,
|
||||||
|
builder_->makeFloatConstant(0.5f)),
|
||||||
|
layer_coordinate);
|
||||||
|
} else if (vol_mag_filter_is_linear) {
|
||||||
|
layer_coordinate = builder_->createNoContractionBinOp(
|
||||||
|
spv::OpFSub, type_float_, layer_coordinate,
|
||||||
|
builder_->makeFloatConstant(0.5f));
|
||||||
|
}
|
||||||
|
// Sample the first layer, needed regardless of whether filtering is
|
||||||
|
// needed.
|
||||||
|
// Floor the array layer (Vulkan does rounding to nearest or + 0.5
|
||||||
|
// and floor even for the layer index, but on the Xenos, addressing
|
||||||
|
// is similar to that of 3D textures). This is needed for both point
|
||||||
|
// and linear filtering (with linear, 0.5 was subtracted
|
||||||
|
// previously).
|
||||||
|
spv::Id layer_0_coordinate = builder_->createUnaryBuiltinCall(
|
||||||
|
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor,
|
||||||
|
layer_coordinate);
|
||||||
id_vector_temp_.clear();
|
id_vector_temp_.clear();
|
||||||
id_vector_temp_.push_back(coordinates[0]);
|
id_vector_temp_.push_back(coordinates[0]);
|
||||||
id_vector_temp_.push_back(coordinates[1]);
|
id_vector_temp_.push_back(coordinates[1]);
|
||||||
id_vector_temp_.push_back(layer_1_coordinate);
|
id_vector_temp_.push_back(layer_0_coordinate);
|
||||||
texture_parameters.coords = builder_->createCompositeConstruct(
|
texture_parameters.coords = builder_->createCompositeConstruct(
|
||||||
type_float3_, id_vector_temp_);
|
type_float3_, id_vector_temp_);
|
||||||
spv::Id layer_lerp_factor = builder_->createUnaryBuiltinCall(
|
|
||||||
type_float_, ext_inst_glsl_std_450_, GLSLstd450Fract,
|
|
||||||
layer_coordinate);
|
|
||||||
spv::Id sample_result_unsigned_stacked_filtered;
|
|
||||||
spv::Id sample_result_signed_stacked_filtered;
|
|
||||||
SampleTexture(
|
SampleTexture(
|
||||||
texture_parameters, image_operands_mask,
|
texture_parameters, image_operands_mask,
|
||||||
image_2d_array_or_cube_unsigned, image_2d_array_or_cube_signed,
|
image_2d_array_or_cube_unsigned, image_2d_array_or_cube_signed,
|
||||||
sampler, is_all_signed, is_any_signed,
|
sampler, is_any_unsigned, is_any_signed,
|
||||||
sample_result_unsigned_stacked_filtered,
|
|
||||||
sample_result_signed_stacked_filtered, layer_lerp_factor,
|
|
||||||
sample_result_unsigned_stacked, sample_result_signed_stacked);
|
sample_result_unsigned_stacked, sample_result_signed_stacked);
|
||||||
if (vol_filter_is_linear != spv::NoResult) {
|
// Sample the second layer if linear filtering is potentially needed
|
||||||
// Get the actual build point after the SampleTexture call for
|
// (conditionally or unconditionally, depending on whether the
|
||||||
// phi.
|
// filter needs to be chosen at runtime), and filter.
|
||||||
spv::Block& block_z_linear_end = *builder_->getBuildPoint();
|
if (vol_filter_is_linear != spv::NoResult ||
|
||||||
builder_->createBranch(&block_z_merge);
|
vol_mag_filter_is_linear) {
|
||||||
builder_->setBuildPoint(&block_z_merge);
|
spv::Block& block_z_head = *builder_->getBuildPoint();
|
||||||
{
|
spv::Block& block_z_linear =
|
||||||
std::unique_ptr<spv::Instruction> filter_phi_op =
|
(vol_filter_is_linear != spv::NoResult)
|
||||||
std::make_unique<spv::Instruction>(
|
? builder_->makeNewBlock()
|
||||||
builder_->getUniqueId(), type_float4_, spv::OpPhi);
|
: block_z_head;
|
||||||
filter_phi_op->addIdOperand(
|
spv::Block& block_z_merge =
|
||||||
sample_result_unsigned_stacked_filtered);
|
(vol_filter_is_linear != spv::NoResult)
|
||||||
filter_phi_op->addIdOperand(block_z_linear_end.getId());
|
? builder_->makeNewBlock()
|
||||||
filter_phi_op->addIdOperand(sample_result_unsigned_stacked);
|
: block_z_head;
|
||||||
filter_phi_op->addIdOperand(block_z_head.getId());
|
if (vol_filter_is_linear != spv::NoResult) {
|
||||||
sample_result_unsigned_stacked = filter_phi_op->getResultId();
|
builder_->createSelectionMerge(
|
||||||
builder_->getBuildPoint()->addInstruction(
|
&block_z_merge, spv::SelectionControlDontFlattenMask);
|
||||||
std::move(filter_phi_op));
|
builder_->createConditionalBranch(
|
||||||
|
vol_filter_is_linear, &block_z_linear, &block_z_merge);
|
||||||
|
builder_->setBuildPoint(&block_z_linear);
|
||||||
}
|
}
|
||||||
{
|
spv::Id layer_1_coordinate = builder_->createBinOp(
|
||||||
std::unique_ptr<spv::Instruction> filter_phi_op =
|
spv::OpFAdd, type_float_, layer_0_coordinate,
|
||||||
std::make_unique<spv::Instruction>(
|
builder_->makeFloatConstant(1.0f));
|
||||||
builder_->getUniqueId(), type_float4_, spv::OpPhi);
|
id_vector_temp_.clear();
|
||||||
filter_phi_op->addIdOperand(
|
id_vector_temp_.push_back(coordinates[0]);
|
||||||
sample_result_signed_stacked_filtered);
|
id_vector_temp_.push_back(coordinates[1]);
|
||||||
filter_phi_op->addIdOperand(block_z_linear_end.getId());
|
id_vector_temp_.push_back(layer_1_coordinate);
|
||||||
filter_phi_op->addIdOperand(sample_result_signed_stacked);
|
texture_parameters.coords = builder_->createCompositeConstruct(
|
||||||
filter_phi_op->addIdOperand(block_z_head.getId());
|
type_float3_, id_vector_temp_);
|
||||||
sample_result_signed_stacked = filter_phi_op->getResultId();
|
spv::Id layer_lerp_factor = builder_->createUnaryBuiltinCall(
|
||||||
builder_->getBuildPoint()->addInstruction(
|
type_float_, ext_inst_glsl_std_450_, GLSLstd450Fract,
|
||||||
std::move(filter_phi_op));
|
layer_coordinate);
|
||||||
|
spv::Id sample_result_unsigned_stacked_filtered;
|
||||||
|
spv::Id sample_result_signed_stacked_filtered;
|
||||||
|
SampleTexture(
|
||||||
|
texture_parameters, image_operands_mask,
|
||||||
|
image_2d_array_or_cube_unsigned,
|
||||||
|
image_2d_array_or_cube_signed, sampler, is_any_unsigned,
|
||||||
|
is_any_signed, sample_result_unsigned_stacked_filtered,
|
||||||
|
sample_result_signed_stacked_filtered, layer_lerp_factor,
|
||||||
|
sample_result_unsigned_stacked, sample_result_signed_stacked);
|
||||||
|
if (vol_filter_is_linear != spv::NoResult) {
|
||||||
|
// Get the actual build point after the SampleTexture call for
|
||||||
|
// phi.
|
||||||
|
spv::Block& block_z_linear_end = *builder_->getBuildPoint();
|
||||||
|
builder_->createBranch(&block_z_merge);
|
||||||
|
builder_->setBuildPoint(&block_z_merge);
|
||||||
|
{
|
||||||
|
std::unique_ptr<spv::Instruction> filter_phi_op =
|
||||||
|
std::make_unique<spv::Instruction>(
|
||||||
|
builder_->getUniqueId(), type_float4_, spv::OpPhi);
|
||||||
|
filter_phi_op->addIdOperand(
|
||||||
|
sample_result_unsigned_stacked_filtered);
|
||||||
|
filter_phi_op->addIdOperand(block_z_linear_end.getId());
|
||||||
|
filter_phi_op->addIdOperand(sample_result_unsigned_stacked);
|
||||||
|
filter_phi_op->addIdOperand(block_z_head.getId());
|
||||||
|
sample_result_unsigned_stacked = filter_phi_op->getResultId();
|
||||||
|
builder_->getBuildPoint()->addInstruction(
|
||||||
|
std::move(filter_phi_op));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::unique_ptr<spv::Instruction> filter_phi_op =
|
||||||
|
std::make_unique<spv::Instruction>(
|
||||||
|
builder_->getUniqueId(), type_float4_, spv::OpPhi);
|
||||||
|
filter_phi_op->addIdOperand(
|
||||||
|
sample_result_signed_stacked_filtered);
|
||||||
|
filter_phi_op->addIdOperand(block_z_linear_end.getId());
|
||||||
|
filter_phi_op->addIdOperand(sample_result_signed_stacked);
|
||||||
|
filter_phi_op->addIdOperand(block_z_head.getId());
|
||||||
|
sample_result_signed_stacked = filter_phi_op->getResultId();
|
||||||
|
builder_->getBuildPoint()->addInstruction(
|
||||||
|
std::move(filter_phi_op));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sample_result_unsigned_stacked =
|
||||||
|
sample_result_unsigned_stacked_filtered;
|
||||||
|
sample_result_signed_stacked =
|
||||||
|
sample_result_signed_stacked_filtered;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
sample_result_unsigned_stacked =
|
|
||||||
sample_result_unsigned_stacked_filtered;
|
|
||||||
sample_result_signed_stacked =
|
|
||||||
sample_result_signed_stacked_filtered;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get the actual build point for phi.
|
if_data_is_3d.makeEndIf();
|
||||||
spv::Block& block_dimension_stacked_end = *builder_->getBuildPoint();
|
|
||||||
builder_->createBranch(&block_dimension_merge);
|
|
||||||
|
|
||||||
// Choose between the 3D and the stacked result based on the actual
|
sample_result_unsigned = if_data_is_3d.createMergePhi(
|
||||||
// data dimensionality.
|
sample_result_unsigned_3d, sample_result_unsigned_stacked);
|
||||||
builder_->setBuildPoint(&block_dimension_merge);
|
sample_result_signed = if_data_is_3d.createMergePhi(
|
||||||
{
|
sample_result_signed_3d, sample_result_signed_stacked);
|
||||||
std::unique_ptr<spv::Instruction> dimension_phi_op =
|
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
|
||||||
type_float4_, spv::OpPhi);
|
|
||||||
dimension_phi_op->addIdOperand(sample_result_unsigned_3d);
|
|
||||||
dimension_phi_op->addIdOperand(block_dimension_3d_end.getId());
|
|
||||||
dimension_phi_op->addIdOperand(sample_result_unsigned_stacked);
|
|
||||||
dimension_phi_op->addIdOperand(block_dimension_stacked_end.getId());
|
|
||||||
sample_result_unsigned = dimension_phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(
|
|
||||||
std::move(dimension_phi_op));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::unique_ptr<spv::Instruction> dimension_phi_op =
|
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
|
||||||
type_float4_, spv::OpPhi);
|
|
||||||
dimension_phi_op->addIdOperand(sample_result_signed_3d);
|
|
||||||
dimension_phi_op->addIdOperand(block_dimension_3d_end.getId());
|
|
||||||
dimension_phi_op->addIdOperand(sample_result_signed_stacked);
|
|
||||||
dimension_phi_op->addIdOperand(block_dimension_stacked_end.getId());
|
|
||||||
sample_result_signed = dimension_phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(
|
|
||||||
std::move(dimension_phi_op));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (use_computed_lod) {
|
if (use_computed_lod) {
|
||||||
texture_parameters.gradX = gradients_h;
|
texture_parameters.gradX = gradients_h;
|
||||||
|
@ -2045,7 +1984,7 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
builder_->createCompositeConstruct(type_float3_, id_vector_temp_);
|
builder_->createCompositeConstruct(type_float3_, id_vector_temp_);
|
||||||
SampleTexture(texture_parameters, image_operands_mask,
|
SampleTexture(texture_parameters, image_operands_mask,
|
||||||
image_2d_array_or_cube_unsigned,
|
image_2d_array_or_cube_unsigned,
|
||||||
image_2d_array_or_cube_signed, sampler, is_all_signed,
|
image_2d_array_or_cube_signed, sampler, is_any_unsigned,
|
||||||
is_any_signed, sample_result_unsigned,
|
is_any_signed, sample_result_unsigned,
|
||||||
sample_result_signed);
|
sample_result_signed);
|
||||||
}
|
}
|
||||||
|
@ -2095,26 +2034,20 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
spv::OpBitwiseAnd, type_uint_, swizzle_word,
|
spv::OpBitwiseAnd, type_uint_, swizzle_word,
|
||||||
builder_->makeUintConstant(swizzle_bit_0_value << 2)),
|
builder_->makeUintConstant(swizzle_bit_0_value << 2)),
|
||||||
const_uint_0_);
|
const_uint_0_);
|
||||||
spv::Block& block_swizzle_head = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder if_swizzle_constant(
|
||||||
spv::Block& block_swizzle_constant = builder_->makeNewBlock();
|
swizzle_bit_2, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
spv::Block& block_swizzle_component = builder_->makeNewBlock();
|
spv::Id swizzle_result_constant;
|
||||||
spv::Block& block_swizzle_merge = builder_->makeNewBlock();
|
{
|
||||||
builder_->createSelectionMerge(
|
// Constant values.
|
||||||
&block_swizzle_merge, spv::SelectionControlDontFlattenMask);
|
// Bit 0 - 0 or 1.
|
||||||
builder_->createConditionalBranch(swizzle_bit_2,
|
swizzle_result_constant = builder_->createTriOp(
|
||||||
&block_swizzle_constant,
|
spv::OpSelect, type_float_, swizzle_bit_0, const_float_1,
|
||||||
&block_swizzle_component);
|
const_float_0_);
|
||||||
// Constant values.
|
}
|
||||||
builder_->setBuildPoint(&block_swizzle_constant);
|
if_swizzle_constant.makeBeginElse();
|
||||||
// Bit 0 - 0 or 1.
|
|
||||||
spv::Id swizzle_result_constant =
|
|
||||||
builder_->createTriOp(spv::OpSelect, type_float_, swizzle_bit_0,
|
|
||||||
const_float_1, const_float_0_);
|
|
||||||
builder_->createBranch(&block_swizzle_merge);
|
|
||||||
// Fetched components.
|
|
||||||
spv::Id swizzle_result_component;
|
spv::Id swizzle_result_component;
|
||||||
{
|
{
|
||||||
builder_->setBuildPoint(&block_swizzle_component);
|
// Fetched components.
|
||||||
// Select whether the result is signed or unsigned (or biased or
|
// Select whether the result is signed or unsigned (or biased or
|
||||||
// gamma-corrected) based on the post-swizzle signedness.
|
// gamma-corrected) based on the post-swizzle signedness.
|
||||||
spv::Id swizzle_sample_result = builder_->createTriOp(
|
spv::Id swizzle_sample_result = builder_->createTriOp(
|
||||||
|
@ -2146,22 +2079,11 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
swizzle_result_component = builder_->createTriOp(
|
swizzle_result_component = builder_->createTriOp(
|
||||||
spv::OpSelect, type_float_, swizzle_bit_1, swizzle_z_or_w,
|
spv::OpSelect, type_float_, swizzle_bit_1, swizzle_z_or_w,
|
||||||
swizzle_x_or_y);
|
swizzle_x_or_y);
|
||||||
builder_->createBranch(&block_swizzle_merge);
|
|
||||||
}
|
}
|
||||||
|
if_swizzle_constant.makeEndIf();
|
||||||
// Select between the constants and the fetched components.
|
// Select between the constants and the fetched components.
|
||||||
builder_->setBuildPoint(&block_swizzle_merge);
|
result[result_component_index] = if_swizzle_constant.createMergePhi(
|
||||||
{
|
swizzle_result_constant, swizzle_result_component);
|
||||||
std::unique_ptr<spv::Instruction> swizzle_phi_op =
|
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
|
||||||
type_float_, spv::OpPhi);
|
|
||||||
swizzle_phi_op->addIdOperand(swizzle_result_constant);
|
|
||||||
swizzle_phi_op->addIdOperand(block_swizzle_constant.getId());
|
|
||||||
swizzle_phi_op->addIdOperand(swizzle_result_component);
|
|
||||||
swizzle_phi_op->addIdOperand(block_swizzle_component.getId());
|
|
||||||
result[result_component_index] = swizzle_phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(
|
|
||||||
std::move(swizzle_phi_op));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2441,58 +2363,43 @@ size_t SpirvShaderTranslator::FindOrAddSamplerBinding(
|
||||||
void SpirvShaderTranslator::SampleTexture(
|
void SpirvShaderTranslator::SampleTexture(
|
||||||
spv::Builder::TextureParameters& texture_parameters,
|
spv::Builder::TextureParameters& texture_parameters,
|
||||||
spv::ImageOperandsMask image_operands_mask, spv::Id image_unsigned,
|
spv::ImageOperandsMask image_operands_mask, spv::Id image_unsigned,
|
||||||
spv::Id image_signed, spv::Id sampler, spv::Id is_all_signed,
|
spv::Id image_signed, spv::Id sampler, spv::Id is_any_unsigned,
|
||||||
spv::Id is_any_signed, spv::Id& result_unsigned_out,
|
spv::Id is_any_signed, spv::Id& result_unsigned_out,
|
||||||
spv::Id& result_signed_out, spv::Id lerp_factor,
|
spv::Id& result_signed_out, spv::Id lerp_factor,
|
||||||
spv::Id lerp_first_unsigned, spv::Id lerp_first_signed) {
|
spv::Id lerp_first_unsigned, spv::Id lerp_first_signed) {
|
||||||
for (uint32_t i = 0; i < 2; ++i) {
|
for (uint32_t i = 0; i < 2; ++i) {
|
||||||
spv::Block& block_sign_head = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder sign_if(i ? is_any_signed : is_any_unsigned,
|
||||||
spv::Block& block_sign = builder_->makeNewBlock();
|
spv::SelectionControlDontFlattenMask,
|
||||||
spv::Block& block_sign_merge = builder_->makeNewBlock();
|
*builder_);
|
||||||
builder_->createSelectionMerge(&block_sign_merge,
|
spv::Id sign_result;
|
||||||
spv::SelectionControlDontFlattenMask);
|
{
|
||||||
// Unsigned (i == 0) - if there are any non-signed components.
|
spv::Id image = i ? image_signed : image_unsigned;
|
||||||
// Signed (i == 1) - if there are any signed components.
|
// OpSampledImage must be in the same block as where its result is used.
|
||||||
builder_->createConditionalBranch(i ? is_any_signed : is_all_signed,
|
texture_parameters.sampler = builder_->createBinOp(
|
||||||
i ? &block_sign : &block_sign_merge,
|
spv::OpSampledImage,
|
||||||
i ? &block_sign_merge : &block_sign);
|
builder_->makeSampledImageType(builder_->getTypeId(image)), image,
|
||||||
builder_->setBuildPoint(&block_sign);
|
sampler);
|
||||||
spv::Id image = i ? image_signed : image_unsigned;
|
sign_result = builder_->createTextureCall(
|
||||||
// OpSampledImage must be in the same block as where its result is used.
|
spv::NoPrecision, type_float4_, false, false, false, false, false,
|
||||||
texture_parameters.sampler = builder_->createBinOp(
|
texture_parameters, image_operands_mask);
|
||||||
spv::OpSampledImage,
|
if (lerp_factor != spv::NoResult) {
|
||||||
builder_->makeSampledImageType(builder_->getTypeId(image)), image,
|
spv::Id lerp_first = i ? lerp_first_signed : lerp_first_unsigned;
|
||||||
sampler);
|
if (lerp_first != spv::NoResult) {
|
||||||
spv::Id result = builder_->createTextureCall(
|
spv::Id lerp_difference = builder_->createNoContractionBinOp(
|
||||||
spv::NoPrecision, type_float4_, false, false, false, false, false,
|
spv::OpVectorTimesScalar, type_float4_,
|
||||||
texture_parameters, image_operands_mask);
|
builder_->createNoContractionBinOp(spv::OpFSub, type_float4_,
|
||||||
if (lerp_factor != spv::NoResult) {
|
sign_result, lerp_first),
|
||||||
spv::Id lerp_first = i ? lerp_first_signed : lerp_first_unsigned;
|
lerp_factor);
|
||||||
if (lerp_first != spv::NoResult) {
|
sign_result = builder_->createNoContractionBinOp(
|
||||||
spv::Id lerp_difference = builder_->createNoContractionBinOp(
|
spv::OpFAdd, type_float4_, sign_result, lerp_difference);
|
||||||
spv::OpVectorTimesScalar, type_float4_,
|
}
|
||||||
builder_->createNoContractionBinOp(spv::OpFSub, type_float4_,
|
|
||||||
result, lerp_first),
|
|
||||||
lerp_factor);
|
|
||||||
result = builder_->createNoContractionBinOp(spv::OpFAdd, type_float4_,
|
|
||||||
result, lerp_difference);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder_->createBranch(&block_sign_merge);
|
sign_if.makeEndIf();
|
||||||
builder_->setBuildPoint(&block_sign_merge);
|
// This may overwrite the first lerp endpoint for the sign (such usage of
|
||||||
{
|
// this function is allowed).
|
||||||
std::unique_ptr<spv::Instruction> phi_op =
|
(i ? result_signed_out : result_unsigned_out) =
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
sign_if.createMergePhi(sign_result, const_float4_0_);
|
||||||
type_float4_, spv::OpPhi);
|
|
||||||
phi_op->addIdOperand(result);
|
|
||||||
phi_op->addIdOperand(block_sign.getId());
|
|
||||||
phi_op->addIdOperand(const_float4_0_);
|
|
||||||
phi_op->addIdOperand(block_sign_head.getId());
|
|
||||||
// This may overwrite the first lerp endpoint for the sign (such usage of
|
|
||||||
// this function is allowed).
|
|
||||||
(i ? result_signed_out : result_unsigned_out) = phi_op->getResultId();
|
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(phi_op));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2500,48 +2407,33 @@ spv::Id SpirvShaderTranslator::QueryTextureLod(
|
||||||
spv::Builder::TextureParameters& texture_parameters, spv::Id image_unsigned,
|
spv::Builder::TextureParameters& texture_parameters, spv::Id image_unsigned,
|
||||||
spv::Id image_signed, spv::Id sampler, spv::Id is_all_signed) {
|
spv::Id image_signed, spv::Id sampler, spv::Id is_all_signed) {
|
||||||
// OpSampledImage must be in the same block as where its result is used.
|
// OpSampledImage must be in the same block as where its result is used.
|
||||||
spv::Block& block_sign_head = *builder_->getBuildPoint();
|
SpirvBuilder::IfBuilder if_signed(
|
||||||
spv::Block& block_sign_signed = builder_->makeNewBlock();
|
is_all_signed, spv::SelectionControlDontFlattenMask, *builder_);
|
||||||
spv::Block& block_sign_unsigned = builder_->makeNewBlock();
|
spv::Id lod_signed;
|
||||||
spv::Block& block_sign_merge = builder_->makeNewBlock();
|
|
||||||
builder_->createSelectionMerge(&block_sign_merge,
|
|
||||||
spv::SelectionControlDontFlattenMask);
|
|
||||||
builder_->createConditionalBranch(is_all_signed, &block_sign_signed,
|
|
||||||
&block_sign_unsigned);
|
|
||||||
builder_->setBuildPoint(&block_sign_signed);
|
|
||||||
texture_parameters.sampler = builder_->createBinOp(
|
|
||||||
spv::OpSampledImage,
|
|
||||||
builder_->makeSampledImageType(builder_->getTypeId(image_signed)),
|
|
||||||
image_signed, sampler);
|
|
||||||
spv::Id lod_signed = builder_->createCompositeExtract(
|
|
||||||
builder_->createTextureQueryCall(spv::OpImageQueryLod, texture_parameters,
|
|
||||||
false),
|
|
||||||
type_float_, 1);
|
|
||||||
builder_->createBranch(&block_sign_merge);
|
|
||||||
builder_->setBuildPoint(&block_sign_unsigned);
|
|
||||||
texture_parameters.sampler = builder_->createBinOp(
|
|
||||||
spv::OpSampledImage,
|
|
||||||
builder_->makeSampledImageType(builder_->getTypeId(image_unsigned)),
|
|
||||||
image_unsigned, sampler);
|
|
||||||
spv::Id lod_unsigned = builder_->createCompositeExtract(
|
|
||||||
builder_->createTextureQueryCall(spv::OpImageQueryLod, texture_parameters,
|
|
||||||
false),
|
|
||||||
type_float_, 1);
|
|
||||||
builder_->createBranch(&block_sign_merge);
|
|
||||||
builder_->setBuildPoint(&block_sign_merge);
|
|
||||||
spv::Id result;
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<spv::Instruction> sign_phi_op =
|
texture_parameters.sampler = builder_->createBinOp(
|
||||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(), type_float_,
|
spv::OpSampledImage,
|
||||||
spv::OpPhi);
|
builder_->makeSampledImageType(builder_->getTypeId(image_signed)),
|
||||||
sign_phi_op->addIdOperand(lod_signed);
|
image_signed, sampler);
|
||||||
sign_phi_op->addIdOperand(block_sign_signed.getId());
|
lod_signed = builder_->createCompositeExtract(
|
||||||
sign_phi_op->addIdOperand(lod_unsigned);
|
builder_->createTextureQueryCall(spv::OpImageQueryLod,
|
||||||
sign_phi_op->addIdOperand(block_sign_unsigned.getId());
|
texture_parameters, false),
|
||||||
result = sign_phi_op->getResultId();
|
type_float_, 1);
|
||||||
builder_->getBuildPoint()->addInstruction(std::move(sign_phi_op));
|
|
||||||
}
|
}
|
||||||
return result;
|
if_signed.makeBeginElse();
|
||||||
|
spv::Id lod_unsigned;
|
||||||
|
{
|
||||||
|
texture_parameters.sampler = builder_->createBinOp(
|
||||||
|
spv::OpSampledImage,
|
||||||
|
builder_->makeSampledImageType(builder_->getTypeId(image_unsigned)),
|
||||||
|
image_unsigned, sampler);
|
||||||
|
lod_unsigned = builder_->createCompositeExtract(
|
||||||
|
builder_->createTextureQueryCall(spv::OpImageQueryLod,
|
||||||
|
texture_parameters, false),
|
||||||
|
type_float_, 1);
|
||||||
|
}
|
||||||
|
if_signed.makeEndIf();
|
||||||
|
return if_signed.createMergePhi(lod_signed, lod_unsigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4156,21 +4156,16 @@ VkShaderModule VulkanRenderTargetCache::GetTransferShader(
|
||||||
builder.createAccessChain(spv::StorageClassPushConstant,
|
builder.createAccessChain(spv::StorageClassPushConstant,
|
||||||
push_constants, id_vector_temp),
|
push_constants, id_vector_temp),
|
||||||
spv::NoPrecision);
|
spv::NoPrecision);
|
||||||
spv::Id stencil_sample_passed = builder.createBinOp(
|
SpirvBuilder::IfBuilder stencil_kill_if(
|
||||||
spv::OpINotEqual, type_bool,
|
builder.createBinOp(
|
||||||
builder.createBinOp(spv::OpBitwiseAnd, type_uint, packed,
|
spv::OpIEqual, type_bool,
|
||||||
stencil_mask_constant),
|
builder.createBinOp(spv::OpBitwiseAnd, type_uint, packed,
|
||||||
builder.makeUintConstant(0));
|
stencil_mask_constant),
|
||||||
spv::Block& stencil_bit_kill_block = builder.makeNewBlock();
|
builder.makeUintConstant(0)),
|
||||||
spv::Block& stencil_bit_merge_block = builder.makeNewBlock();
|
spv::SelectionControlMaskNone, builder);
|
||||||
builder.createSelectionMerge(&stencil_bit_merge_block,
|
|
||||||
spv::SelectionControlMaskNone);
|
|
||||||
builder.createConditionalBranch(stencil_sample_passed,
|
|
||||||
&stencil_bit_merge_block,
|
|
||||||
&stencil_bit_kill_block);
|
|
||||||
builder.setBuildPoint(&stencil_bit_kill_block);
|
|
||||||
builder.createNoResultOp(spv::OpKill);
|
builder.createNoResultOp(spv::OpKill);
|
||||||
builder.setBuildPoint(&stencil_bit_merge_block);
|
// OpKill terminates the block.
|
||||||
|
stencil_kill_if.makeEndIf(false);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue