[Vulkan] Non-GS point sprites + minor SPIR-V fixes
This commit is contained in:
@@ -111,6 +111,7 @@ void SpirvShaderTranslator::Reset() {
|
||||
input_front_facing_ = spv::NoResult;
|
||||
std::fill(input_output_interpolators_.begin(),
|
||||
input_output_interpolators_.end(), spv::NoResult);
|
||||
output_point_coordinates_ = spv::NoResult;
|
||||
output_point_size_ = spv::NoResult;
|
||||
|
||||
sampler_bindings_.clear();
|
||||
@@ -1097,18 +1098,33 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderBeforeMain() {
|
||||
|
||||
Modification shader_modification = GetSpirvShaderModification();
|
||||
|
||||
// Create the point size output. Not using gl_PointSize from gl_PerVertex not
|
||||
// to rely on the shaderTessellationAndGeometryPointSize feature, and also
|
||||
// because the value written to gl_PointSize must be greater than zero.
|
||||
if (shader_modification.vertex.output_point_size) {
|
||||
output_point_size_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_float_, "xe_out_point_size");
|
||||
builder_->addDecoration(output_point_size_, spv::DecorationLocation,
|
||||
int(output_location));
|
||||
builder_->addDecoration(output_point_size_, spv::DecorationInvariant);
|
||||
main_interface_.push_back(output_point_size_);
|
||||
++output_location;
|
||||
if (shader_modification.vertex.output_point_parameters) {
|
||||
if (shader_modification.vertex.host_vertex_shader_type ==
|
||||
Shader::HostVertexShaderType::kPointListAsTriangleStrip) {
|
||||
// Create the point coordinates output.
|
||||
output_point_coordinates_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_float2_, "xe_out_point_coordinates");
|
||||
builder_->addDecoration(output_point_coordinates_,
|
||||
spv::DecorationLocation, int(output_location));
|
||||
builder_->addDecoration(output_point_coordinates_,
|
||||
spv::DecorationInvariant);
|
||||
main_interface_.push_back(output_point_coordinates_);
|
||||
++output_location;
|
||||
} else {
|
||||
// Create the point size output. Not using gl_PointSize from gl_PerVertex
|
||||
// not to rely on the shaderTessellationAndGeometryPointSize feature, and
|
||||
// also because the value written to gl_PointSize must be greater than
|
||||
// zero.
|
||||
output_point_size_ =
|
||||
builder_->createVariable(spv::NoPrecision, spv::StorageClassOutput,
|
||||
type_float_, "xe_out_point_size");
|
||||
builder_->addDecoration(output_point_size_, spv::DecorationLocation,
|
||||
int(output_location));
|
||||
builder_->addDecoration(output_point_size_, spv::DecorationInvariant);
|
||||
main_interface_.push_back(output_point_size_);
|
||||
++output_location;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the gl_PerVertex output for used system outputs.
|
||||
@@ -1172,24 +1188,33 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||
}
|
||||
}
|
||||
|
||||
Modification shader_modification = GetSpirvShaderModification();
|
||||
|
||||
// TODO(Triang3l): For HostVertexShaderType::kRectangeListAsTriangleStrip,
|
||||
// start the vertex loop, and load the index there.
|
||||
|
||||
// Load the vertex index or the tessellation parameters.
|
||||
if (register_count()) {
|
||||
// TODO(Triang3l): Barycentric coordinates and patch index.
|
||||
if (IsSpirvVertexShader()) {
|
||||
// TODO(Triang3l): Close line loop primitive.
|
||||
// Load the unswapped index as uint for swapping, or for indirect loading
|
||||
// if needed.
|
||||
spv::Id vertex_index = builder_->createUnaryOp(
|
||||
spv::OpBitcast, type_uint_,
|
||||
builder_->createLoad(input_vertex_index_, spv::NoPrecision));
|
||||
if (!features_.full_draw_index_uint32) {
|
||||
// Check if the full 32-bit index needs to be loaded indirectly.
|
||||
if (shader_modification.vertex.host_vertex_shader_type ==
|
||||
Shader::HostVertexShaderType::kPointListAsTriangleStrip) {
|
||||
// Load the point index, autogenerated or indirectly from the index
|
||||
// buffer.
|
||||
// Extract the primitive index from the two-triangle strip vertex index.
|
||||
spv::Id const_uint_2 = builder_->makeUintConstant(2);
|
||||
vertex_index = builder_->createBinOp(
|
||||
spv::OpShiftRightLogical, type_uint_, vertex_index, const_uint_2);
|
||||
// Check if the index needs to be loaded from the index buffer.
|
||||
spv::Id load_vertex_index = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_VertexIndexLoad))),
|
||||
builder_->makeUintConstant(static_cast<unsigned int>(
|
||||
kSysFlag_ComputeOrPrimitiveVertexIndexLoad))),
|
||||
const_uint_0_);
|
||||
spv::Block& block_load_vertex_index_pre = *builder_->getBuildPoint();
|
||||
spv::Block& block_load_vertex_index_start = builder_->makeNewBlock();
|
||||
@@ -1200,25 +1225,61 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||
&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.
|
||||
// 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::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)));
|
||||
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);
|
||||
@@ -1238,19 +1299,81 @@ void SpirvShaderTranslator::StartVertexOrTessEvalShaderInMain() {
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(loaded_vertex_index_phi_op));
|
||||
}
|
||||
} else {
|
||||
// TODO(Triang3l): Close line loop primitive.
|
||||
// Load the unswapped index as uint for swapping, or for indirect
|
||||
// loading if needed.
|
||||
if (!features_.full_draw_index_uint32) {
|
||||
// Check if the full 32-bit index needs to be loaded indirectly.
|
||||
spv::Id load_vertex_index = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_VertexIndexLoad))),
|
||||
const_uint_0_);
|
||||
spv::Block& block_load_vertex_index_pre = *builder_->getBuildPoint();
|
||||
spv::Block& block_load_vertex_index_start = builder_->makeNewBlock();
|
||||
spv::Block& block_load_vertex_index_merge = builder_->makeNewBlock();
|
||||
SpirvCreateSelectionMerge(block_load_vertex_index_merge.getId(),
|
||||
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 =
|
||||
std::make_unique<spv::Instruction>(builder_->getUniqueId(),
|
||||
type_uint_, spv::OpPhi);
|
||||
loaded_vertex_index_phi_op->addIdOperand(loaded_vertex_index);
|
||||
loaded_vertex_index_phi_op->addIdOperand(
|
||||
block_load_vertex_index_end.getId());
|
||||
loaded_vertex_index_phi_op->addIdOperand(vertex_index);
|
||||
loaded_vertex_index_phi_op->addIdOperand(
|
||||
block_load_vertex_index_pre.getId());
|
||||
vertex_index = loaded_vertex_index_phi_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(loaded_vertex_index_phi_op));
|
||||
}
|
||||
}
|
||||
// Endian-swap the index.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(
|
||||
builder_->makeIntConstant(kSystemConstantVertexIndexEndian));
|
||||
vertex_index = EndianSwap32Uint(
|
||||
vertex_index, builder_->createLoad(
|
||||
builder_->createAccessChain(
|
||||
spv::StorageClassUniform,
|
||||
uniform_system_constants_, id_vector_temp_),
|
||||
spv::NoPrecision));
|
||||
}
|
||||
// Endian-swap the index and convert to int.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(
|
||||
builder_->makeIntConstant(kSystemConstantVertexIndexEndian));
|
||||
spv::Id vertex_index_endian =
|
||||
builder_->createLoad(builder_->createAccessChain(
|
||||
spv::StorageClassUniform,
|
||||
uniform_system_constants_, id_vector_temp_),
|
||||
spv::NoPrecision);
|
||||
vertex_index = builder_->createUnaryOp(
|
||||
spv::OpBitcast, type_int_,
|
||||
EndianSwap32Uint(vertex_index, vertex_index_endian));
|
||||
// Convert the index to a signed integer.
|
||||
vertex_index =
|
||||
builder_->createUnaryOp(spv::OpBitcast, type_int_, vertex_index);
|
||||
// Add the base to the index.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(
|
||||
@@ -1301,61 +1424,66 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {
|
||||
builder_->createTriOp(spv::OpSelect, type_float_, is_w_not_reciprocal,
|
||||
position_w, guest_position_w_inv);
|
||||
|
||||
// Check if the shader returns XY/W rather than XY, and if it does, revert
|
||||
// that.
|
||||
// TODO(Triang3l): Check if having XY or Z pre-divided by W should result in
|
||||
// affine interpolation.
|
||||
uint_vector_temp_.clear();
|
||||
uint_vector_temp_.reserve(2);
|
||||
uint_vector_temp_.push_back(0);
|
||||
uint_vector_temp_.push_back(1);
|
||||
spv::Id position_xy = builder_->createRvalueSwizzle(
|
||||
spv::NoPrecision, type_float2_, guest_position, uint_vector_temp_);
|
||||
spv::Id is_xy_divided_by_w = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_XYDividedByW))),
|
||||
const_uint_0_);
|
||||
spv::Id guest_position_xy_mul_w = builder_->createBinOp(
|
||||
spv::OpVectorTimesScalar, type_float2_, position_xy, position_w);
|
||||
builder_->addDecoration(guest_position_xy_mul_w,
|
||||
spv::DecorationNoContraction);
|
||||
position_xy =
|
||||
builder_->createTriOp(spv::OpSelect, type_float2_, is_xy_divided_by_w,
|
||||
guest_position_xy_mul_w, position_xy);
|
||||
|
||||
// Check if the shader returns Z/W rather than Z, and if it does, revert that.
|
||||
// TODO(Triang3l): Check if having XY or Z pre-divided by W should result in
|
||||
// affine interpolation.
|
||||
spv::Id position_z =
|
||||
builder_->createCompositeExtract(guest_position, type_float_, 2);
|
||||
spv::Id is_z_divided_by_w = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_ZDividedByW))),
|
||||
const_uint_0_);
|
||||
spv::Id guest_position_z_mul_w =
|
||||
builder_->createBinOp(spv::OpFMul, type_float_, position_z, position_w);
|
||||
builder_->addDecoration(guest_position_z_mul_w, spv::DecorationNoContraction);
|
||||
position_z =
|
||||
builder_->createTriOp(spv::OpSelect, type_float_, is_z_divided_by_w,
|
||||
guest_position_z_mul_w, position_z);
|
||||
|
||||
// Build XYZ of the position with W format handled.
|
||||
spv::Id position_xyz;
|
||||
|
||||
// Open a scope since position_xy and position_z won't be synchronized anymore
|
||||
// after position_xyz is built and modified later.
|
||||
{
|
||||
std::unique_ptr<spv::Instruction> composite_construct_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), type_float3_, spv::OpCompositeConstruct);
|
||||
composite_construct_op->addIdOperand(position_xy);
|
||||
composite_construct_op->addIdOperand(position_z);
|
||||
position_xyz = composite_construct_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(composite_construct_op));
|
||||
// Check if the shader returns XY/W rather than XY, and if it does, revert
|
||||
// that.
|
||||
uint_vector_temp_.clear();
|
||||
uint_vector_temp_.reserve(2);
|
||||
uint_vector_temp_.push_back(0);
|
||||
uint_vector_temp_.push_back(1);
|
||||
spv::Id position_xy = builder_->createRvalueSwizzle(
|
||||
spv::NoPrecision, type_float2_, guest_position, uint_vector_temp_);
|
||||
spv::Id is_xy_divided_by_w = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_XYDividedByW))),
|
||||
const_uint_0_);
|
||||
spv::Id guest_position_xy_mul_w = builder_->createBinOp(
|
||||
spv::OpVectorTimesScalar, type_float2_, position_xy, position_w);
|
||||
builder_->addDecoration(guest_position_xy_mul_w,
|
||||
spv::DecorationNoContraction);
|
||||
position_xy = builder_->createTriOp(
|
||||
spv::OpSelect, type_float2_,
|
||||
builder_->smearScalar(spv::NoPrecision, is_xy_divided_by_w,
|
||||
type_bool2_),
|
||||
guest_position_xy_mul_w, position_xy);
|
||||
|
||||
// Check if the shader returns Z/W rather than Z, and if it does, revert
|
||||
// that.
|
||||
spv::Id position_z =
|
||||
builder_->createCompositeExtract(guest_position, type_float_, 2);
|
||||
spv::Id is_z_divided_by_w = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint_, main_system_constant_flags_,
|
||||
builder_->makeUintConstant(
|
||||
static_cast<unsigned int>(kSysFlag_ZDividedByW))),
|
||||
const_uint_0_);
|
||||
spv::Id guest_position_z_mul_w =
|
||||
builder_->createBinOp(spv::OpFMul, type_float_, position_z, position_w);
|
||||
builder_->addDecoration(guest_position_z_mul_w,
|
||||
spv::DecorationNoContraction);
|
||||
position_z =
|
||||
builder_->createTriOp(spv::OpSelect, type_float_, is_z_divided_by_w,
|
||||
guest_position_z_mul_w, position_z);
|
||||
|
||||
// Build XYZ of the position with W format handled.
|
||||
{
|
||||
std::unique_ptr<spv::Instruction> composite_construct_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), type_float3_, spv::OpCompositeConstruct);
|
||||
composite_construct_op->addIdOperand(position_xy);
|
||||
composite_construct_op->addIdOperand(position_z);
|
||||
position_xyz = composite_construct_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(composite_construct_op));
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the NDC scale and offset for guest to host viewport transformation.
|
||||
@@ -1382,20 +1510,6 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {
|
||||
ndc_offset_mul_w);
|
||||
builder_->addDecoration(position_xyz, spv::DecorationNoContraction);
|
||||
|
||||
// Store the position converted to the host.
|
||||
spv::Id position;
|
||||
{
|
||||
std::unique_ptr<spv::Instruction> composite_construct_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), type_float4_, spv::OpCompositeConstruct);
|
||||
composite_construct_op->addIdOperand(position_xyz);
|
||||
composite_construct_op->addIdOperand(position_w);
|
||||
position = composite_construct_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(composite_construct_op));
|
||||
}
|
||||
builder_->createStore(position, position_ptr);
|
||||
|
||||
// Write the point size.
|
||||
if (output_point_size_ != spv::NoResult) {
|
||||
spv::Id point_size;
|
||||
@@ -1415,6 +1529,154 @@ void SpirvShaderTranslator::CompleteVertexOrTessEvalShaderInMain() {
|
||||
}
|
||||
builder_->createStore(point_size, output_point_size_);
|
||||
}
|
||||
|
||||
Modification shader_modification = GetSpirvShaderModification();
|
||||
|
||||
// Expand the point sprite.
|
||||
if (shader_modification.vertex.host_vertex_shader_type ==
|
||||
Shader::HostVertexShaderType::kPointListAsTriangleStrip) {
|
||||
// Top-left, bottom-left, top-right, bottom-right order (chosen arbitrarily,
|
||||
// simply based on counterclockwise meaning front with
|
||||
// frontFace = VkFrontFace(0), but faceness is ignored for non-polygon
|
||||
// primitive types).
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.reserve(2);
|
||||
id_vector_temp_.push_back(builder_->makeUintConstant(0b10));
|
||||
id_vector_temp_.push_back(builder_->makeUintConstant(0b01));
|
||||
spv::Id point_vertex_positive = builder_->createBinOp(
|
||||
spv::OpINotEqual, type_bool2_,
|
||||
builder_->createBinOp(
|
||||
spv::OpBitwiseAnd, type_uint2_,
|
||||
builder_->smearScalar(spv::NoPrecision,
|
||||
builder_->createUnaryOp(
|
||||
spv::OpBitcast, type_uint_,
|
||||
builder_->createLoad(input_vertex_index_,
|
||||
spv::NoPrecision)),
|
||||
type_uint2_),
|
||||
builder_->createCompositeConstruct(type_uint2_, id_vector_temp_)),
|
||||
SpirvSmearScalarResultOrConstant(const_uint_0_, type_uint2_));
|
||||
|
||||
// Load the point diameter in guest pixels, with the override from the
|
||||
// vertex shader if provided.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(
|
||||
builder_->makeIntConstant(kSystemConstantPointConstantDiameter));
|
||||
spv::Id point_guest_diameter = builder_->createLoad(
|
||||
builder_->createAccessChain(spv::StorageClassUniform,
|
||||
uniform_system_constants_, id_vector_temp_),
|
||||
spv::NoPrecision);
|
||||
if (current_shader().writes_point_size_edge_flag_kill_vertex() & 0b001) {
|
||||
assert_true(var_main_point_size_edge_flag_kill_vertex_ != spv::NoResult);
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(const_int_0_);
|
||||
spv::Id point_vertex_diameter = builder_->createLoad(
|
||||
builder_->createAccessChain(
|
||||
spv::StorageClassFunction,
|
||||
var_main_point_size_edge_flag_kill_vertex_, id_vector_temp_),
|
||||
spv::NoPrecision);
|
||||
// The vertex shader's header writes -1.0 to point_size by default, so any
|
||||
// non-negative value means that it was overwritten by the translated
|
||||
// vertex shader, and needs to be used instead of the constant size. The
|
||||
// per-vertex diameter has already been clamped earlier in translation
|
||||
// (combined with making it non-negative).
|
||||
point_guest_diameter = builder_->createTriOp(
|
||||
spv::OpSelect, type_float2_,
|
||||
builder_->smearScalar(
|
||||
spv::NoPrecision,
|
||||
builder_->createBinOp(spv::OpFOrdGreaterThanEqual, type_bool_,
|
||||
point_vertex_diameter, const_float_0_),
|
||||
type_bool2_),
|
||||
builder_->smearScalar(spv::NoPrecision, point_vertex_diameter,
|
||||
type_float2_),
|
||||
point_guest_diameter);
|
||||
}
|
||||
// Transform the diameter in the guest screen coordinates to radius in the
|
||||
// normalized device coordinates.
|
||||
id_vector_temp_.clear();
|
||||
id_vector_temp_.push_back(builder_->makeIntConstant(
|
||||
kSystemConstantPointScreenDiameterToNdcRadius));
|
||||
spv::Id point_radius = builder_->createBinOp(
|
||||
spv::OpFMul, type_float2_, point_guest_diameter,
|
||||
builder_->createLoad(builder_->createAccessChain(
|
||||
spv::StorageClassUniform,
|
||||
uniform_system_constants_, id_vector_temp_),
|
||||
spv::NoPrecision));
|
||||
builder_->addDecoration(point_radius, spv::DecorationNoContraction);
|
||||
// Transform the radius from the normalized device coordinates to the clip
|
||||
// space.
|
||||
point_radius = builder_->createBinOp(spv::OpVectorTimesScalar, type_float2_,
|
||||
point_radius, position_w);
|
||||
builder_->addDecoration(point_radius, spv::DecorationNoContraction);
|
||||
|
||||
// Apply the direction of expansion for the current host vertex.
|
||||
spv::Id point_radius_negative =
|
||||
builder_->createUnaryOp(spv::OpFNegate, type_float2_, point_radius);
|
||||
builder_->addDecoration(point_radius_negative,
|
||||
spv::DecorationNoContraction);
|
||||
// Expand the point sprite.
|
||||
uint_vector_temp_.clear();
|
||||
uint_vector_temp_.reserve(2);
|
||||
uint_vector_temp_.push_back(0);
|
||||
uint_vector_temp_.push_back(1);
|
||||
spv::Id point_position_xy = builder_->createBinOp(
|
||||
spv::OpFAdd, type_float2_,
|
||||
builder_->createRvalueSwizzle(spv::NoPrecision, type_float2_,
|
||||
position_xyz, uint_vector_temp_),
|
||||
builder_->createTriOp(spv::OpSelect, type_float2_,
|
||||
point_vertex_positive, point_radius,
|
||||
point_radius_negative));
|
||||
builder_->addDecoration(point_position_xy, spv::DecorationNoContraction);
|
||||
// Store the position.
|
||||
spv::Id position;
|
||||
{
|
||||
// Bypass the `getNumTypeConstituents(typeId) == (int)constituents.size()`
|
||||
// assertion in createCompositeConstruct, OpCompositeConstruct can
|
||||
// construct vectors not only from scalars, but also from other vectors.
|
||||
std::unique_ptr<spv::Instruction> composite_construct_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), type_float4_, spv::OpCompositeConstruct);
|
||||
composite_construct_op->addIdOperand(point_position_xy);
|
||||
composite_construct_op->addIdOperand(
|
||||
builder_->createCompositeExtract(position_xyz, type_float_, 2));
|
||||
composite_construct_op->addIdOperand(position_w);
|
||||
position = composite_construct_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(composite_construct_op));
|
||||
}
|
||||
builder_->createStore(position, position_ptr);
|
||||
|
||||
// Write the point coordinates.
|
||||
if (output_point_coordinates_ != spv::NoResult) {
|
||||
builder_->createStore(
|
||||
builder_->createTriOp(spv::OpSelect, type_float2_,
|
||||
point_vertex_positive, const_float2_1_,
|
||||
const_float2_0_),
|
||||
output_point_coordinates_);
|
||||
}
|
||||
|
||||
// TODO(Triang3l): For points, handle ps_ucp_mode (take the guest clip space
|
||||
// coordinates instead of the host ones, calculate the distances to the user
|
||||
// clip planes, cull using the distance from the center for modes 0, 1 and
|
||||
// 2, cull and clip per-vertex for modes 2 and 3) in clip and cull
|
||||
// distances.
|
||||
} else {
|
||||
// Store the position converted to the host.
|
||||
spv::Id position;
|
||||
{
|
||||
// Bypass the `getNumTypeConstituents(typeId) == (int)constituents.size()`
|
||||
// assertion in createCompositeConstruct, OpCompositeConstruct can
|
||||
// construct vectors not only from scalars, but also from other vectors.
|
||||
std::unique_ptr<spv::Instruction> composite_construct_op =
|
||||
std::make_unique<spv::Instruction>(
|
||||
builder_->getUniqueId(), type_float4_, spv::OpCompositeConstruct);
|
||||
composite_construct_op->addIdOperand(position_xyz);
|
||||
composite_construct_op->addIdOperand(position_w);
|
||||
position = composite_construct_op->getResultId();
|
||||
builder_->getBuildPoint()->addInstruction(
|
||||
std::move(composite_construct_op));
|
||||
}
|
||||
builder_->createStore(position, position_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvShaderTranslator::StartFragmentShaderBeforeMain() {
|
||||
|
||||
Reference in New Issue
Block a user