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 "VertexProcessor.hpp"
16
17 #include "Pipeline/Constants.hpp"
18 #include "Pipeline/VertexProgram.hpp"
19 #include "System/Debug.hpp"
20 #include "System/Math.hpp"
21 #include "Vulkan/VkPipelineLayout.hpp"
22
23 #include <cstring>
24
25 namespace sw {
26
clear()27 void VertexCache::clear()
28 {
29 for(uint32_t i = 0; i < SIZE; i++)
30 {
31 tag[i] = 0xFFFFFFFF;
32 }
33 }
34
computeHash()35 uint32_t VertexProcessor::States::computeHash()
36 {
37 uint32_t *state = reinterpret_cast<uint32_t *>(this);
38 uint32_t hash = 0;
39
40 for(unsigned int i = 0; i < sizeof(States) / sizeof(uint32_t); i++)
41 {
42 hash ^= state[i];
43 }
44
45 return hash;
46 }
47
operator ==(const State & state) const48 bool VertexProcessor::State::operator==(const State &state) const
49 {
50 if(hash != state.hash)
51 {
52 return false;
53 }
54
55 return *static_cast<const States *>(this) == static_cast<const States &>(state);
56 }
57
VertexProcessor()58 VertexProcessor::VertexProcessor()
59 {
60 setRoutineCacheSize(1024);
61 }
62
setRoutineCacheSize(int cacheSize)63 void VertexProcessor::setRoutineCacheSize(int cacheSize)
64 {
65 routineCache = std::make_unique<RoutineCacheType>(clamp(cacheSize, 1, 65536));
66 }
67
update(const vk::GraphicsState & pipelineState,const sw::SpirvShader * vertexShader,const vk::Inputs & inputs)68 const VertexProcessor::State VertexProcessor::update(const vk::GraphicsState &pipelineState, const sw::SpirvShader *vertexShader, const vk::Inputs &inputs)
69 {
70 const vk::VertexInputInterfaceState &vertexInputInterfaceState = pipelineState.getVertexInputInterfaceState();
71 const vk::PreRasterizationState &preRasterizationState = pipelineState.getPreRasterizationState();
72
73 State state;
74
75 state.shaderID = vertexShader->getIdentifier();
76 state.pipelineLayoutIdentifier = preRasterizationState.getPipelineLayout()->identifier;
77 state.robustBufferAccess = vertexShader->getRobustBufferAccess();
78 state.isPoint = vertexInputInterfaceState.getTopology() == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
79 state.depthClipEnable = preRasterizationState.getDepthClipEnable();
80 state.depthClipNegativeOneToOne = preRasterizationState.getDepthClipNegativeOneToOne();
81
82 for(size_t i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
83 {
84 state.input[i].format = inputs.getStream(i).format;
85 // TODO: get rid of attribType -- just keep the VK format all the way through, this fully determines
86 // how to handle the attribute.
87 state.input[i].attribType = vertexShader->inputs[i * 4].Type;
88 }
89
90 state.hash = state.computeHash();
91
92 return state;
93 }
94
routine(const State & state,const vk::PipelineLayout * pipelineLayout,const SpirvShader * vertexShader,const vk::DescriptorSet::Bindings & descriptorSets)95 VertexProcessor::RoutineType VertexProcessor::routine(const State &state,
96 const vk::PipelineLayout *pipelineLayout,
97 const SpirvShader *vertexShader,
98 const vk::DescriptorSet::Bindings &descriptorSets)
99 {
100 auto routine = routineCache->lookup(state);
101
102 if(!routine) // Create one
103 {
104 VertexRoutine *generator = new VertexProgram(state, pipelineLayout, vertexShader, descriptorSets);
105 generator->generate();
106 routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
107 delete generator;
108
109 routineCache->add(state, routine);
110 }
111
112 return routine;
113 }
114
115 } // namespace sw
116