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/VertexProgram.hpp"
18#include "Pipeline/Constants.hpp"
19#include "System/Math.hpp"
20#include "Vulkan/VkDebug.hpp"
21
22#include <cstring>
23
24namespace sw
25{
26 void VertexCache::clear()
27 {
28 for(uint32_t i = 0; i < SIZE; i++)
29 {
30 tag[i] = 0xFFFFFFFF;
31 }
32 }
33
34 uint32_t VertexProcessor::States::computeHash()
35 {
36 uint32_t *state = reinterpret_cast<uint32_t*>(this);
37 uint32_t hash = 0;
38
39 for(unsigned int i = 0; i < sizeof(States) / sizeof(uint32_t); i++)
40 {
41 hash ^= state[i];
42 }
43
44 return hash;
45 }
46
47 unsigned int VertexProcessor::States::Input::bytesPerAttrib() const
48 {
49 switch(type)
50 {
51 case STREAMTYPE_FLOAT:
52 case STREAMTYPE_INT:
53 case STREAMTYPE_UINT:
54 return count * sizeof(uint32_t);
55 case STREAMTYPE_HALF:
56 case STREAMTYPE_SHORT:
57 case STREAMTYPE_USHORT:
58 return count * sizeof(uint16_t);
59 case STREAMTYPE_BYTE:
60 case STREAMTYPE_SBYTE:
61 return count * sizeof(uint8_t);
62 case STREAMTYPE_COLOR:
63 case STREAMTYPE_2_10_10_10_INT:
64 case STREAMTYPE_2_10_10_10_UINT:
65 return sizeof(int);
66 default:
67 UNSUPPORTED("stream.type %d", int(type));
68 }
69
70 return 0;
71 }
72
73 bool VertexProcessor::State::operator==(const State &state) const
74 {
75 if(hash != state.hash)
76 {
77 return false;
78 }
79
80 static_assert(is_memcmparable<State>::value, "Cannot memcmp States");
81 return memcmp(static_cast<const States*>(this), static_cast<const States*>(&state), sizeof(States)) == 0;
82 }
83
84 VertexProcessor::VertexProcessor()
85 {
86 routineCache = nullptr;
87 setRoutineCacheSize(1024);
88 }
89
90 VertexProcessor::~VertexProcessor()
91 {
92 delete routineCache;
93 routineCache = nullptr;
94 }
95
96 void VertexProcessor::setRoutineCacheSize(int cacheSize)
97 {
98 delete routineCache;
99 routineCache = new RoutineCacheType(clamp(cacheSize, 1, 65536));
100 }
101
102 const VertexProcessor::State VertexProcessor::update(const sw::Context* context)
103 {
104 State state;
105
106 state.shaderID = context->vertexShader->getSerialID();
107 state.robustBufferAccess = context->robustBufferAccess;
108 state.isPoint = context->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
109
110 for(int i = 0; i < MAX_INTERFACE_COMPONENTS / 4; i++)
111 {
112 state.input[i].type = context->input[i].type;
113 state.input[i].count = context->input[i].count;
114 state.input[i].normalized = context->input[i].normalized;
115 // TODO: get rid of attribType -- just keep the VK format all the way through, this fully determines
116 // how to handle the attribute.
117 state.input[i].attribType = context->vertexShader->inputs[i*4].Type;
118 }
119
120 state.hash = state.computeHash();
121
122 return state;
123 }
124
125 VertexProcessor::RoutineType VertexProcessor::routine(const State &state,
126 vk::PipelineLayout const *pipelineLayout,
127 SpirvShader const *vertexShader,
128 const vk::DescriptorSet::Bindings &descriptorSets)
129 {
130 auto routine = routineCache->query(state);
131
132 if(!routine) // Create one
133 {
134 VertexRoutine *generator = new VertexProgram(state, pipelineLayout, vertexShader, descriptorSets);
135 generator->generate();
136 routine = (*generator)("VertexRoutine_%0.8X", state.shaderID);
137 delete generator;
138
139 routineCache->add(state, routine);
140 }
141
142 return routine;
143 }
144}
145