[Vulkan] Rectangle and quad list geometry shader generation

This commit is contained in:
Triang3l
2022-05-10 21:48:18 +03:00
parent b9256fcdbd
commit 73d574a046
8 changed files with 846 additions and 608 deletions

View File

@@ -11,9 +11,12 @@
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
#include "third_party/glslang/SPIRV/SpvBuilder.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
@@ -33,11 +36,6 @@ namespace xe {
namespace gpu {
namespace vulkan {
// Generated with `xb buildshaders`.
namespace shaders {
#include "xenia/gpu/shaders/bytecode/vulkan_spirv/primitive_rectangle_list_gs.h"
} // namespace shaders
VulkanPipelineCache::VulkanPipelineCache(
VulkanCommandProcessor& command_processor,
const RegisterFile& register_file,
@@ -51,20 +49,6 @@ VulkanPipelineCache::~VulkanPipelineCache() { Shutdown(); }
bool VulkanPipelineCache::Initialize() {
const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider();
const VkPhysicalDeviceFeatures& device_features = provider.device_features();
if (device_features.geometryShader) {
gs_rectangle_list_ = ui::vulkan::util::CreateShaderModule(
provider, shaders::primitive_rectangle_list_gs,
sizeof(shaders::primitive_rectangle_list_gs));
if (gs_rectangle_list_ == VK_NULL_HANDLE) {
XELOGE(
"VulkanPipelineCache: Failed to create the rectangle list geometry "
"shader");
Shutdown();
return false;
}
}
shader_translator_ = std::make_unique<SpirvShaderTranslator>(
SpirvShaderTranslator::Features(provider));
@@ -80,10 +64,14 @@ void VulkanPipelineCache::Shutdown() {
ClearCache();
shader_translator_.reset();
for (const auto& geometry_shader_pair : geometry_shaders_) {
if (geometry_shader_pair.second != VK_NULL_HANDLE) {
dfn.vkDestroyShaderModule(device, geometry_shader_pair.second, nullptr);
}
}
geometry_shaders_.clear();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyShaderModule, device,
gs_rectangle_list_);
shader_translator_.reset();
}
void VulkanPipelineCache::ClearCache() {
@@ -255,6 +243,14 @@ bool VulkanPipelineCache::ConfigurePipeline(
if (!pipeline_layout) {
return false;
}
VkShaderModule geometry_shader = VK_NULL_HANDLE;
GeometryShaderKey geometry_shader_key;
if (GetGeometryShaderKey(description.geometry_shader, geometry_shader_key)) {
geometry_shader = GetGeometryShader(geometry_shader_key);
if (geometry_shader == VK_NULL_HANDLE) {
return false;
}
}
VkRenderPass render_pass =
render_target_cache_.GetRenderPass(render_pass_key);
if (render_pass == VK_NULL_HANDLE) {
@@ -266,6 +262,7 @@ bool VulkanPipelineCache::ConfigurePipeline(
creation_arguments.pipeline = &pipeline;
creation_arguments.vertex_shader = vertex_shader;
creation_arguments.pixel_shader = pixel_shader;
creation_arguments.geometry_shader = geometry_shader;
creation_arguments.render_pass = render_pass;
if (!EnsurePipelineCreated(creation_arguments)) {
return false;
@@ -419,6 +416,7 @@ bool VulkanPipelineCache::GetCurrentStateDescription(
primitive_topology = PipelinePrimitiveTopology::kTriangleList;
break;
case xenos::PrimitiveType::kQuadList:
geometry_shader = PipelineGeometryShader::kQuadList;
primitive_topology = PipelinePrimitiveTopology::kLineListWithAdjacency;
break;
default:
@@ -686,6 +684,782 @@ bool VulkanPipelineCache::ArePipelineRequirementsMet(
return true;
}
bool VulkanPipelineCache::GetGeometryShaderKey(
PipelineGeometryShader geometry_shader_type, GeometryShaderKey& key_out) {
if (geometry_shader_type == PipelineGeometryShader::kNone) {
return false;
}
GeometryShaderKey key;
key.type = geometry_shader_type;
// TODO(Triang3l): Make the linkage parameters depend on the real needs of the
// vertex and the pixel shader.
key.interpolator_count = xenos::kMaxInterpolators;
key.user_clip_plane_count = /* 6 */ 0;
key.user_clip_plane_cull = 0;
key.has_vertex_kill_and = /* 1 */ 0;
key.has_point_size = /* 1 */ 0;
key.has_point_coordinates = /* 1 */ 0;
key_out = key;
return true;
}
VkShaderModule VulkanPipelineCache::GetGeometryShader(GeometryShaderKey key) {
auto it = geometry_shaders_.find(key);
if (it != geometry_shaders_.end()) {
return it->second;
}
std::vector<spv::Id> id_vector_temp;
std::vector<unsigned int> uint_vector_temp;
spv::ExecutionMode input_primitive_execution_mode = spv::ExecutionMode(0);
uint32_t input_primitive_vertex_count = 0;
spv::ExecutionMode output_primitive_execution_mode = spv::ExecutionMode(0);
uint32_t output_max_vertices = 0;
switch (key.type) {
case PipelineGeometryShader::kRectangleList:
// Triangle to a strip of 2 triangles.
input_primitive_execution_mode = spv::ExecutionModeTriangles;
input_primitive_vertex_count = 3;
output_primitive_execution_mode = spv::ExecutionModeOutputTriangleStrip;
output_max_vertices = 4;
break;
case PipelineGeometryShader::kQuadList:
// 4 vertices passed via a line list with adjacency to a strip of 2
// triangles.
input_primitive_execution_mode = spv::ExecutionModeInputLinesAdjacency;
input_primitive_vertex_count = 4;
output_primitive_execution_mode = spv::ExecutionModeOutputTriangleStrip;
output_max_vertices = 4;
break;
default:
assert_unhandled_case(key.type);
}
uint32_t clip_distance_count =
key.user_clip_plane_cull ? 0 : key.user_clip_plane_count;
uint32_t cull_distance_count =
(key.user_clip_plane_cull ? key.user_clip_plane_count : 0) +
key.has_vertex_kill_and;
spv::Builder builder(spv::Spv_1_0,
(SpirvShaderTranslator::kSpirvMagicToolId << 16) | 1,
nullptr);
spv::Id ext_inst_glsl_std_450 = builder.import("GLSL.std.450");
builder.addCapability(spv::CapabilityGeometry);
if (clip_distance_count) {
builder.addCapability(spv::CapabilityClipDistance);
}
if (cull_distance_count) {
builder.addCapability(spv::CapabilityCullDistance);
}
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
builder.setSource(spv::SourceLanguageUnknown, 0);
// TODO(Triang3l): Shader float controls (NaN preservation most importantly).
std::vector<spv::Id> main_interface;
spv::Id type_void = builder.makeVoidType();
spv::Id type_bool = builder.makeBoolType();
spv::Id type_bool4 = builder.makeVectorType(type_bool, 4);
spv::Id type_int = builder.makeIntType(32);
spv::Id type_float = builder.makeFloatType(32);
spv::Id type_float4 = builder.makeVectorType(type_float, 4);
spv::Id type_clip_distances =
clip_distance_count
? builder.makeArrayType(
type_float, builder.makeUintConstant(clip_distance_count), 0)
: spv::NoType;
spv::Id type_cull_distances =
cull_distance_count
? builder.makeArrayType(
type_float, builder.makeUintConstant(cull_distance_count), 0)
: spv::NoType;
spv::Id type_interpolators =
key.interpolator_count
? builder.makeArrayType(
type_float4, builder.makeUintConstant(key.interpolator_count),
0)
: spv::NoType;
spv::Id type_point_coordinates = key.has_point_coordinates
? builder.makeVectorType(type_float, 2)
: spv::NoType;
// Inputs and outputs - matching glslang order, in gl_PerVertex gl_in[],
// user-defined outputs, user-defined inputs, out gl_PerVertex.
// TODO(Triang3l): Point parameters from the system uniform buffer.
spv::Id const_input_primitive_vertex_count =
builder.makeUintConstant(input_primitive_vertex_count);
// in gl_PerVertex gl_in[].
// gl_Position.
id_vector_temp.clear();
uint32_t member_in_gl_per_vertex_position = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_float4);
spv::Id const_member_in_gl_per_vertex_position =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_position));
// gl_ClipDistance.
uint32_t member_in_gl_per_vertex_clip_distance = UINT32_MAX;
spv::Id const_member_in_gl_per_vertex_clip_distance = spv::NoResult;
if (clip_distance_count) {
member_in_gl_per_vertex_clip_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_clip_distances);
const_member_in_gl_per_vertex_clip_distance =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_clip_distance));
}
// gl_CullDistance.
uint32_t member_in_gl_per_vertex_cull_distance = UINT32_MAX;
if (cull_distance_count) {
member_in_gl_per_vertex_cull_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_cull_distances);
}
// Structure and array.
spv::Id type_struct_in_gl_per_vertex =
builder.makeStructType(id_vector_temp, "gl_PerVertex");
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_position, "gl_Position");
builder.addMemberDecoration(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_position,
spv::DecorationBuiltIn, spv::BuiltInPosition);
if (clip_distance_count) {
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_clip_distance,
"gl_ClipDistance");
builder.addMemberDecoration(
type_struct_in_gl_per_vertex, member_in_gl_per_vertex_clip_distance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
}
if (cull_distance_count) {
builder.addMemberName(type_struct_in_gl_per_vertex,
member_in_gl_per_vertex_cull_distance,
"gl_CullDistance");
builder.addMemberDecoration(
type_struct_in_gl_per_vertex, member_in_gl_per_vertex_cull_distance,
spv::DecorationBuiltIn, spv::BuiltInCullDistance);
}
builder.addDecoration(type_struct_in_gl_per_vertex, spv::DecorationBlock);
spv::Id type_array_in_gl_per_vertex = builder.makeArrayType(
type_struct_in_gl_per_vertex, const_input_primitive_vertex_count, 0);
spv::Id in_gl_per_vertex =
builder.createVariable(spv::NoPrecision, spv::StorageClassInput,
type_array_in_gl_per_vertex, "gl_in");
main_interface.push_back(in_gl_per_vertex);
// Interpolators output.
spv::Id out_interpolators = spv::NoResult;
if (key.interpolator_count) {
out_interpolators =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_interpolators, "xe_out_interpolators");
builder.addDecoration(out_interpolators, spv::DecorationLocation, 0);
builder.addDecoration(out_interpolators, spv::DecorationInvariant);
main_interface.push_back(out_interpolators);
}
// Point coordinate output.
spv::Id out_point_coordinates = spv::NoResult;
if (key.has_point_coordinates) {
out_point_coordinates = builder.createVariable(
spv::NoPrecision, spv::StorageClassOutput, type_point_coordinates,
"xe_out_point_coordinates");
builder.addDecoration(out_point_coordinates, spv::DecorationLocation,
key.interpolator_count);
builder.addDecoration(out_point_coordinates, spv::DecorationInvariant);
main_interface.push_back(out_point_coordinates);
}
// Interpolator input.
spv::Id in_interpolators = spv::NoResult;
if (key.interpolator_count) {
in_interpolators = builder.createVariable(
spv::NoPrecision, spv::StorageClassInput,
builder.makeArrayType(type_interpolators,
const_input_primitive_vertex_count, 0),
"xe_in_interpolators");
builder.addDecoration(in_interpolators, spv::DecorationLocation, 0);
main_interface.push_back(in_interpolators);
}
// Point size input.
spv::Id in_point_size = spv::NoResult;
if (key.has_point_size) {
in_point_size = builder.createVariable(
spv::NoPrecision, spv::StorageClassInput,
builder.makeArrayType(type_float, const_input_primitive_vertex_count,
0),
"xe_in_point_size");
builder.addDecoration(in_point_size, spv::DecorationLocation,
key.interpolator_count);
main_interface.push_back(in_point_size);
}
// out gl_PerVertex.
// gl_Position.
id_vector_temp.clear();
uint32_t member_out_gl_per_vertex_position = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_float4);
spv::Id const_member_out_gl_per_vertex_position =
builder.makeIntConstant(int32_t(member_out_gl_per_vertex_position));
// gl_ClipDistance.
uint32_t member_out_gl_per_vertex_clip_distance = UINT32_MAX;
spv::Id const_member_out_gl_per_vertex_clip_distance = spv::NoResult;
if (clip_distance_count) {
member_out_gl_per_vertex_clip_distance = uint32_t(id_vector_temp.size());
id_vector_temp.push_back(type_clip_distances);
const_member_out_gl_per_vertex_clip_distance = builder.makeIntConstant(
int32_t(member_out_gl_per_vertex_clip_distance));
}
// Structure.
spv::Id type_struct_out_gl_per_vertex =
builder.makeStructType(id_vector_temp, "gl_PerVertex");
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position, "gl_Position");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationInvariant);
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_position,
spv::DecorationBuiltIn, spv::BuiltInPosition);
if (clip_distance_count) {
builder.addMemberName(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
"gl_ClipDistance");
builder.addMemberDecoration(type_struct_out_gl_per_vertex,
member_out_gl_per_vertex_clip_distance,
spv::DecorationInvariant);
builder.addMemberDecoration(
type_struct_out_gl_per_vertex, member_out_gl_per_vertex_clip_distance,
spv::DecorationBuiltIn, spv::BuiltInClipDistance);
}
builder.addDecoration(type_struct_out_gl_per_vertex, spv::DecorationBlock);
spv::Id out_gl_per_vertex =
builder.createVariable(spv::NoPrecision, spv::StorageClassOutput,
type_struct_out_gl_per_vertex, "");
main_interface.push_back(out_gl_per_vertex);
// Begin the main function.
std::vector<spv::Id> main_param_types;
std::vector<std::vector<spv::Decoration>> main_precisions;
spv::Block* main_entry;
spv::Function* main_function =
builder.makeFunctionEntry(spv::NoPrecision, type_void, "main",
main_param_types, main_precisions, &main_entry);
spv::Instruction* entry_point =
builder.addEntryPoint(spv::ExecutionModelGeometry, main_function, "main");
for (spv::Id interface_id : main_interface) {
entry_point->addIdOperand(interface_id);
}
builder.addExecutionMode(main_function, input_primitive_execution_mode);
builder.addExecutionMode(main_function, spv::ExecutionModeInvocations, 1);
builder.addExecutionMode(main_function, output_primitive_execution_mode);
builder.addExecutionMode(main_function, spv::ExecutionModeOutputVertices,
int(output_max_vertices));
// Note that after every OpEmitVertex, all output variables are undefined.
// Discard the whole primitive if any vertex has a NaN position (may also be
// set to NaN for emulation of vertex killing with the OR operator).
for (uint32_t i = 0; i < input_primitive_vertex_count; ++i) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(i)));
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id position_is_nan = builder.createUnaryOp(
spv::OpAny, type_bool,
builder.createUnaryOp(
spv::OpIsNan, type_bool4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision)));
spv::Block& discard_predecessor = *builder.getBuildPoint();
spv::Block& discard_then_block = builder.makeNewBlock();
spv::Block& discard_merge_block = builder.makeNewBlock();
{
std::unique_ptr<spv::Instruction> selection_merge_op(
std::make_unique<spv::Instruction>(spv::OpSelectionMerge));
selection_merge_op->addIdOperand(discard_merge_block.getId());
selection_merge_op->addImmediateOperand(
spv::SelectionControlDontFlattenMask);
discard_predecessor.addInstruction(std::move(selection_merge_op));
}
{
std::unique_ptr<spv::Instruction> branch_conditional_op(
std::make_unique<spv::Instruction>(spv::OpBranchConditional));
branch_conditional_op->addIdOperand(position_is_nan);
branch_conditional_op->addIdOperand(discard_then_block.getId());
branch_conditional_op->addIdOperand(discard_merge_block.getId());
branch_conditional_op->addImmediateOperand(1);
branch_conditional_op->addImmediateOperand(2);
discard_predecessor.addInstruction(std::move(branch_conditional_op));
}
discard_then_block.addPredecessor(&discard_predecessor);
discard_merge_block.addPredecessor(&discard_predecessor);
builder.setBuildPoint(&discard_then_block);
builder.createNoResultOp(spv::OpReturn);
builder.setBuildPoint(&discard_merge_block);
}
// Cull the whole primitive if any cull distance for all vertices in the
// primitive is < 0.
// TODO(Triang3l): For points, handle ps_ucp_mode (transform the host clip
// space to the guest one, 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) - except for the vertex kill flag.
if (cull_distance_count) {
spv::Id const_member_in_gl_per_vertex_cull_distance =
builder.makeIntConstant(int32_t(member_in_gl_per_vertex_cull_distance));
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
spv::Id cull_condition = spv::NoResult;
for (uint32_t i = 0; i < cull_distance_count; ++i) {
for (uint32_t j = 0; j < input_primitive_vertex_count; ++j) {
id_vector_temp.clear();
id_vector_temp.reserve(3);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(j)));
id_vector_temp.push_back(const_member_in_gl_per_vertex_cull_distance);
id_vector_temp.push_back(builder.makeIntConstant(int32_t(i)));
spv::Id cull_distance_is_negative = builder.createBinOp(
spv::OpFOrdLessThan, type_bool,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
const_float_0);
if (cull_condition != spv::NoResult) {
cull_condition =
builder.createBinOp(spv::OpLogicalAnd, type_bool, cull_condition,
cull_distance_is_negative);
} else {
cull_condition = cull_distance_is_negative;
}
}
}
assert_true(cull_condition != spv::NoResult);
spv::Block& discard_predecessor = *builder.getBuildPoint();
spv::Block& discard_then_block = builder.makeNewBlock();
spv::Block& discard_merge_block = builder.makeNewBlock();
{
std::unique_ptr<spv::Instruction> selection_merge_op(
std::make_unique<spv::Instruction>(spv::OpSelectionMerge));
selection_merge_op->addIdOperand(discard_merge_block.getId());
selection_merge_op->addImmediateOperand(
spv::SelectionControlDontFlattenMask);
discard_predecessor.addInstruction(std::move(selection_merge_op));
}
{
std::unique_ptr<spv::Instruction> branch_conditional_op(
std::make_unique<spv::Instruction>(spv::OpBranchConditional));
branch_conditional_op->addIdOperand(cull_condition);
branch_conditional_op->addIdOperand(discard_then_block.getId());
branch_conditional_op->addIdOperand(discard_merge_block.getId());
branch_conditional_op->addImmediateOperand(1);
branch_conditional_op->addImmediateOperand(2);
discard_predecessor.addInstruction(std::move(branch_conditional_op));
}
discard_then_block.addPredecessor(&discard_predecessor);
discard_merge_block.addPredecessor(&discard_predecessor);
builder.setBuildPoint(&discard_then_block);
builder.createNoResultOp(spv::OpReturn);
builder.setBuildPoint(&discard_merge_block);
}
switch (key.type) {
case PipelineGeometryShader::kRectangleList: {
// Construct a strip with the fourth vertex generated by mirroring a
// vertex across the longest edge (the diagonal).
//
// Possible options:
//
// 0---1
// | /|
// | / | - 12 is the longest edge, strip 0123 (most commonly used)
// |/ | v3 = v0 + (v1 - v0) + (v2 - v0), or v3 = -v0 + v1 + v2
// 2--[3]
//
// 1---2
// | /|
// | / | - 20 is the longest edge, strip 1203
// |/ |
// 0--[3]
//
// 2---0
// | /|
// | / | - 01 is the longest edge, strip 2013
// |/ |
// 1--[3]
spv::Id const_int_0 = builder.makeIntConstant(0);
spv::Id const_int_1 = builder.makeIntConstant(1);
spv::Id const_int_2 = builder.makeIntConstant(2);
spv::Id const_int_3 = builder.makeIntConstant(3);
// Get squares of edge lengths to choose the longest edge.
// [0] - 12, [1] - 20, [2] - 01.
spv::Id edge_lengths[3];
id_vector_temp.resize(3);
id_vector_temp[1] = const_member_in_gl_per_vertex_position;
for (uint32_t i = 0; i < 3; ++i) {
id_vector_temp[0] = builder.makeIntConstant(int32_t((1 + i) % 3));
id_vector_temp[2] = const_int_0;
spv::Id edge_0_x = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[2] = const_int_1;
spv::Id edge_0_y = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = builder.makeIntConstant(int32_t((2 + i) % 3));
id_vector_temp[2] = const_int_0;
spv::Id edge_1_x = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[2] = const_int_1;
spv::Id edge_1_y = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
spv::Id edge_x =
builder.createBinOp(spv::OpFSub, type_float, edge_1_x, edge_0_x);
spv::Id edge_y =
builder.createBinOp(spv::OpFSub, type_float, edge_1_y, edge_0_y);
edge_lengths[i] = builder.createBinOp(
spv::OpFAdd, type_float,
builder.createBinOp(spv::OpFMul, type_float, edge_x, edge_x),
builder.createBinOp(spv::OpFMul, type_float, edge_y, edge_y));
}
// Choose the index of the first vertex in the strip based on which edge
// is the longest, and calculate the indices of the other vertices.
spv::Id vertex_indices[3];
// If 12 > 20 && 12 > 01, then 12 is the longest edge, and the strip is
// 0123. Otherwise, if 20 > 01, then 20 is the longest, and the strip is
// 1203, but if not, 01 is the longest, and the strip is 2013.
vertex_indices[0] = builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(
spv::OpLogicalAnd, type_bool,
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[0], edge_lengths[1]),
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[0], edge_lengths[2])),
const_int_0,
builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(spv::OpFOrdGreaterThan, type_bool,
edge_lengths[1], edge_lengths[2]),
const_int_1, const_int_2));
for (uint32_t i = 1; i < 3; ++i) {
// vertex_indices[i] = (vertex_indices[0] + i) % 3
spv::Id vertex_index_without_wrapping =
builder.createBinOp(spv::OpIAdd, type_int, vertex_indices[0],
builder.makeIntConstant(int32_t(i)));
vertex_indices[i] = builder.createTriOp(
spv::OpSelect, type_int,
builder.createBinOp(spv::OpSLessThan, type_bool,
vertex_index_without_wrapping, const_int_3),
vertex_index_without_wrapping,
builder.createBinOp(spv::OpISub, type_int,
vertex_index_without_wrapping, const_int_3));
}
// Initialize the point coordinates output for safety if this shader type
// is used with has_point_coordinates for some reason.
spv::Id const_point_coordinates_zero = spv::NoResult;
if (key.has_point_coordinates) {
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_float_0);
id_vector_temp.push_back(const_float_0);
const_point_coordinates_zero = builder.makeCompositeConstant(
type_point_coordinates, id_vector_temp);
}
// Emit the triangle in the strip that consists of the original vertices.
for (uint32_t i = 0; i < 3; ++i) {
spv::Id vertex_index = vertex_indices[i];
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(vertex_index);
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
// Clip distances.
if (clip_distance_count) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
spv::Id vertex_clip_distances = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(
const_member_out_gl_per_vertex_clip_distance);
builder.createStore(
vertex_clip_distances,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
}
// Construct the fourth vertex.
// Interpolators.
for (uint32_t i = 0; i < key.interpolator_count; ++i) {
spv::Id const_int_i = builder.makeIntConstant(int32_t(i));
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_int_i);
spv::Id vertex_interpolator_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_interpolators,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_interpolator_v01 = builder.createBinOp(
spv::OpFSub, type_float4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
vertex_interpolator_v0);
builder.addDecoration(vertex_interpolator_v01,
spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_interpolator_v3 = builder.createBinOp(
spv::OpFAdd, type_float4, vertex_interpolator_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_interpolator_v3,
spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.push_back(const_int_i);
builder.createStore(
vertex_interpolator_v3,
builder.createAccessChain(spv::StorageClassOutput,
out_interpolators, id_vector_temp));
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_position_v01 = builder.createBinOp(
spv::OpFSub, type_float4,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
vertex_position_v0);
builder.addDecoration(vertex_position_v01, spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_position_v3 = builder.createBinOp(
spv::OpFAdd, type_float4, vertex_position_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_position_v3, spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position_v3,
builder.createAccessChain(spv::StorageClassOutput, out_gl_per_vertex,
id_vector_temp));
// Clip distances.
for (uint32_t i = 0; i < clip_distance_count; ++i) {
spv::Id const_int_i = builder.makeIntConstant(int32_t(i));
id_vector_temp.clear();
id_vector_temp.reserve(3);
id_vector_temp.push_back(vertex_indices[0]);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
id_vector_temp.push_back(const_int_i);
spv::Id vertex_clip_distance_v0 = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp[0] = vertex_indices[1];
spv::Id vertex_clip_distance_v01 = builder.createBinOp(
spv::OpFSub, type_float,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision),
vertex_clip_distance_v0);
builder.addDecoration(vertex_clip_distance_v01,
spv::DecorationNoContraction);
id_vector_temp[0] = vertex_indices[2];
spv::Id vertex_clip_distance_v3 = builder.createBinOp(
spv::OpFAdd, type_float, vertex_clip_distance_v01,
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision));
builder.addDecoration(vertex_clip_distance_v3,
spv::DecorationNoContraction);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
id_vector_temp.push_back(const_int_i);
builder.createStore(
vertex_clip_distance_v3,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
builder.createNoResultOp(spv::OpEndPrimitive);
} break;
case PipelineGeometryShader::kQuadList: {
// Initialize the point coordinates output for safety if this shader type
// is used with has_point_coordinates for some reason.
spv::Id const_point_coordinates_zero = spv::NoResult;
if (key.has_point_coordinates) {
spv::Id const_float_0 = builder.makeFloatConstant(0.0f);
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_float_0);
id_vector_temp.push_back(const_float_0);
const_point_coordinates_zero = builder.makeCompositeConstant(
type_point_coordinates, id_vector_temp);
}
// Build the triangle strip from the original quad vertices in the
// 0, 1, 3, 2 order (like specified for GL_QUAD_STRIP).
// TODO(Triang3l): Find the correct decomposition of quads into triangles
// on the real hardware.
for (uint32_t i = 0; i < 4; ++i) {
spv::Id const_vertex_index =
builder.makeIntConstant(int32_t(i ^ (i >> 1)));
// Interpolators.
if (key.interpolator_count) {
id_vector_temp.clear();
id_vector_temp.push_back(const_vertex_index);
builder.createStore(
builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_interpolators, id_vector_temp),
spv::NoPrecision),
out_interpolators);
}
// Point coordinates.
if (key.has_point_coordinates) {
builder.createStore(const_point_coordinates_zero,
out_point_coordinates);
}
// Position.
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_position);
spv::Id vertex_position = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput, in_gl_per_vertex,
id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(const_member_out_gl_per_vertex_position);
builder.createStore(
vertex_position,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
// Clip distances.
if (clip_distance_count) {
id_vector_temp.clear();
id_vector_temp.reserve(2);
id_vector_temp.push_back(const_vertex_index);
id_vector_temp.push_back(const_member_in_gl_per_vertex_clip_distance);
spv::Id vertex_clip_distances = builder.createLoad(
builder.createAccessChain(spv::StorageClassInput,
in_gl_per_vertex, id_vector_temp),
spv::NoPrecision);
id_vector_temp.clear();
id_vector_temp.push_back(
const_member_out_gl_per_vertex_clip_distance);
builder.createStore(
vertex_clip_distances,
builder.createAccessChain(spv::StorageClassOutput,
out_gl_per_vertex, id_vector_temp));
}
// Emit the vertex.
builder.createNoResultOp(spv::OpEmitVertex);
}
builder.createNoResultOp(spv::OpEndPrimitive);
} break;
default:
assert_unhandled_case(key.type);
}
// End the main function.
builder.leaveFunction();
// Serialize the shader code.
std::vector<unsigned int> shader_code;
builder.dump(shader_code);
// Create the shader module, and store the handle even if creation fails not
// to try to create it again later.
const ui::vulkan::VulkanProvider& provider =
command_processor_.GetVulkanProvider();
VkShaderModule shader_module = ui::vulkan::util::CreateShaderModule(
provider, reinterpret_cast<const uint32_t*>(shader_code.data()),
sizeof(uint32_t) * shader_code.size());
if (shader_module == VK_NULL_HANDLE) {
XELOGE(
"VulkanPipelineCache: Failed to create the primitive type geometry "
"shader 0x{:08X}",
key.key);
}
geometry_shaders_.emplace(key, shader_module);
return shader_module;
}
bool VulkanPipelineCache::EnsurePipelineCreated(
const PipelineCreationArguments& creation_arguments) {
if (creation_arguments.pipeline->second.pipeline != VK_NULL_HANDLE) {
@@ -739,15 +1513,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
shader_stage_vertex.pName = "main";
shader_stage_vertex.pSpecializationInfo = nullptr;
// Geometry shader.
VkShaderModule geometry_shader = VK_NULL_HANDLE;
switch (description.geometry_shader) {
case PipelineGeometryShader::kRectangleList:
geometry_shader = gs_rectangle_list_;
break;
default:
break;
}
if (geometry_shader != VK_NULL_HANDLE) {
if (creation_arguments.geometry_shader != VK_NULL_HANDLE) {
VkPipelineShaderStageCreateInfo& shader_stage_geometry =
shader_stages[shader_stage_count++];
shader_stage_geometry.sType =
@@ -755,7 +1521,7 @@ bool VulkanPipelineCache::EnsurePipelineCreated(
shader_stage_geometry.pNext = nullptr;
shader_stage_geometry.flags = 0;
shader_stage_geometry.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
shader_stage_geometry.module = geometry_shader;
shader_stage_geometry.module = creation_arguments.geometry_shader;
shader_stage_geometry.pName = "main";
shader_stage_geometry.pSpecializationInfo = nullptr;
}