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 State state;
71
72 state.shaderID = vertexShader->getSerialID();
73 state.pipelineLayoutIdentifier = pipelineState.getPipelineLayout()->identifier;
74 state.robustBufferAccess = pipelineState.getRobustBufferAccess();
75 state.isPoint = pipelineState.getTopology() == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
76
77 for(size_t i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
78 {
79 state.input[i].format = inputs.getStream(i).format;
80 // TODO: get rid of attribType -- just keep the VK format all the way through, this fully determines
81 // how to handle the attribute.
82 state.input[i].attribType = vertexShader->inputs[i * 4].Type;
83 }
84
85 state.hash = state.computeHash();
86
87 return state;
88 }
89
routine(const State & state,vk::PipelineLayout const * pipelineLayout,SpirvShader const * vertexShader,const vk::DescriptorSet::Bindings & descriptorSets)90 VertexProcessor::RoutineType VertexProcessor::routine(const State &state,
91 vk::PipelineLayout const *pipelineLayout,
92 SpirvShader const *vertexShader,
93 const vk::DescriptorSet::Bindings &descriptorSets)
94 {
95 auto routine = routineCache->lookup(state);
96
97 if(!routine) // Create one
98 {
99 VertexRoutine *generator = new VertexProgram(state, pipelineLayout, vertexShader, descriptorSets);
100 generator->generate();
101 routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
102 delete generator;
103
104 routineCache->add(state, routine);
105 }
106
107 return routine;
108 }
109
110 } // namespace sw
111