1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "VertexProgram.hpp"
16
17 #include "SamplerCore.hpp"
18 #include "Device/Renderer.hpp"
19 #include "Device/Vertex.hpp"
20 #include "System/Debug.hpp"
21 #include "System/Half.hpp"
22 #include "Vulkan/VkDevice.hpp"
23 #include "Vulkan/VkPipelineLayout.hpp"
24
25 namespace sw {
26
VertexProgram(const VertexProcessor::State & state,const vk::PipelineLayout * pipelineLayout,const SpirvShader * spirvShader,const vk::DescriptorSet::Bindings & descriptorSets)27 VertexProgram::VertexProgram(
28 const VertexProcessor::State &state,
29 const vk::PipelineLayout *pipelineLayout,
30 const SpirvShader *spirvShader,
31 const vk::DescriptorSet::Bindings &descriptorSets)
32 : VertexRoutine(state, pipelineLayout, spirvShader)
33 , descriptorSets(descriptorSets)
34 {
35 routine.setImmutableInputBuiltins(spirvShader);
36
37 // TODO(b/146486064): Consider only assigning these to the SpirvRoutine iff
38 // they are ever going to be read.
39 routine.layer = *Pointer<Int>(data + OFFSET(DrawData, layer));
40 routine.instanceID = *Pointer<Int>(data + OFFSET(DrawData, instanceID));
41
42 routine.setInputBuiltin(spirvShader, spv::BuiltInViewIndex, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
43 assert(builtin.SizeInComponents == 1);
44 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine.layer));
45 });
46
47 routine.setInputBuiltin(spirvShader, spv::BuiltInInstanceIndex, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
48 // TODO: we could do better here; we know InstanceIndex is uniform across all lanes
49 assert(builtin.SizeInComponents == 1);
50 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(routine.instanceID));
51 });
52
53 routine.setInputBuiltin(spirvShader, spv::BuiltInSubgroupSize, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
54 ASSERT(builtin.SizeInComponents == 1);
55 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(SIMD::Width));
56 });
57
58 routine.device = device;
59 routine.descriptorSets = data + OFFSET(DrawData, descriptorSets);
60 routine.descriptorDynamicOffsets = data + OFFSET(DrawData, descriptorDynamicOffsets);
61 routine.pushConstants = data + OFFSET(DrawData, pushConstants);
62 routine.constants = device + OFFSET(vk::Device, constants);
63 }
64
~VertexProgram()65 VertexProgram::~VertexProgram()
66 {
67 }
68
program(Pointer<UInt> & batch,UInt & vertexCount)69 void VertexProgram::program(Pointer<UInt> &batch, UInt &vertexCount)
70 {
71 routine.vertexIndex = *Pointer<SIMD::Int>(As<Pointer<SIMD::Int>>(batch)) +
72 SIMD::Int(*Pointer<Int>(data + OFFSET(DrawData, baseVertex)));
73
74 auto it = spirvShader->inputBuiltins.find(spv::BuiltInVertexIndex);
75 if(it != spirvShader->inputBuiltins.end())
76 {
77 assert(it->second.SizeInComponents == 1);
78 routine.getVariable(it->second.Id)[it->second.FirstComponent] =
79 As<SIMD::Float>(routine.vertexIndex);
80 }
81
82 auto activeLaneMask = SIMD::Int(0xFFFFFFFF);
83 ASSERT(SIMD::Width == 4);
84 SIMD::Int storesAndAtomicsMask = CmpGE(SIMD::UInt(vertexCount), SIMD::UInt(1, 2, 3, 4));
85 spirvShader->emit(&routine, activeLaneMask, storesAndAtomicsMask, descriptorSets);
86
87 spirvShader->emitEpilog(&routine);
88 }
89
90 } // namespace sw
91