am 9252e819: Remove tessellation.user_defined_io.per_patch cases from must pass.
[platform/upstream/VK-GL-CTS.git] / executor / xeCallQueue.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Test Executor
3  * ------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Cross-thread function call dispatcher.
22  *//*--------------------------------------------------------------------*/
23
24 #include "xeCallQueue.hpp"
25 #include "deInt32.h"
26 #include "deMemory.h"
27
28 using std::vector;
29
30 static inline int getNextQueueSize (int curSize, int minNewSize)
31 {
32         return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize));
33 }
34
35 namespace xe
36 {
37
38 // CallQueue
39
40 CallQueue::CallQueue (void)
41         : m_callSem             (0)
42         , m_callQueue   (64)
43 {
44 }
45
46 CallQueue::~CallQueue (void)
47 {
48         // Destroy all calls.
49         for (vector<Call*>::iterator i = m_calls.begin(); i != m_calls.end(); i++)
50                 delete *i;
51 }
52
53 void CallQueue::callNext (void)
54 {
55         Call* call = DE_NULL;
56
57         // Wait for a call.
58         m_callSem.decrement();
59
60         // Acquire call from buffer.
61         {
62                 de::ScopedLock lock(m_lock);
63                 call = m_callQueue.popBack();
64         }
65
66         try
67         {
68                 // \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call.
69                 call->getFunction()(CallReader(call));
70                 call->clear();
71         }
72         catch (const std::exception&)
73         {
74                 try
75                 {
76                         // Try to push call into free calls list.
77                         de::ScopedLock lock(m_lock);
78                         m_freeCalls.push_back(call);
79                 }
80                 catch (const std::exception&)
81                 {
82                         // We can't do anything but ignore this.
83                 }
84
85                 throw;
86         }
87
88         // Push back to free calls list.
89         {
90                 de::ScopedLock lock(m_lock);
91                 m_freeCalls.push_back(call);
92         }
93 }
94
95 Call* CallQueue::getEmptyCall (void)
96 {
97         de::ScopedLock  lock    (m_lock);
98         Call*                   call    = DE_NULL;
99
100         // Try to get from free calls list.
101         if (!m_freeCalls.empty())
102         {
103                 call = m_freeCalls.back();
104                 m_freeCalls.pop_back();
105         }
106
107         // If no free calls were available, create a new.
108         if (!call)
109         {
110                 m_calls.reserve(m_calls.size()+1);
111                 call = new Call();
112                 m_calls.push_back(call);
113         }
114
115         return call;
116 }
117
118 void CallQueue::enqueue (Call* call)
119 {
120         de::ScopedLock lock(m_lock);
121
122         if (m_callQueue.getNumFree() == 0)
123         {
124                 // Call queue must be grown.
125                 m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize()+1));
126         }
127
128         m_callQueue.pushFront(call);
129         m_callSem.increment();
130 }
131
132 void CallQueue::freeCall (Call* call)
133 {
134         de::ScopedLock lock(m_lock);
135         m_freeCalls.push_back(call);
136 }
137
138 // Call
139
140 Call::Call (void)
141         : m_func(DE_NULL)
142 {
143 }
144
145 Call::~Call (void)
146 {
147 }
148
149 void Call::clear (void)
150 {
151         m_func = DE_NULL;
152         m_data.clear();
153 }
154
155 // CallReader
156
157 CallReader::CallReader (Call* call)
158         : m_call        (call)
159         , m_curPos      (0)
160 {
161 }
162
163 void CallReader::read (deUint8* bytes, int numBytes)
164 {
165         DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
166         deMemcpy(bytes, m_call->getData()+m_curPos, numBytes);
167         m_curPos += numBytes;
168 }
169
170 const deUint8* CallReader::getDataBlock (int numBytes)
171 {
172         DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
173
174         const deUint8* ptr = m_call->getData()+m_curPos;
175         m_curPos += numBytes;
176
177         return ptr;
178 }
179
180 CallReader& operator>> (CallReader& reader, std::string& value)
181 {
182         value.clear();
183         for (;;)
184         {
185                 char c;
186                 reader.read((deUint8*)&c, sizeof(char));
187                 if (c != 0)
188                         value.push_back(c);
189                 else
190                         break;
191         }
192
193         return reader;
194 }
195
196 // CallWriter
197
198 CallWriter::CallWriter (CallQueue* queue, Call::Function function)
199         : m_queue               (queue)
200         , m_call                (queue->getEmptyCall())
201         , m_enqueued    (false)
202 {
203         m_call->setFunction(function);
204 }
205
206 CallWriter::~CallWriter (void)
207 {
208         if (!m_enqueued)
209                 m_queue->freeCall(m_call);
210 }
211
212 void CallWriter::write (const deUint8* bytes, int numBytes)
213 {
214         DE_ASSERT(!m_enqueued);
215         int curPos = m_call->getDataSize();
216         m_call->setDataSize(curPos+numBytes);
217         deMemcpy(m_call->getData()+curPos, bytes, numBytes);
218 }
219
220 void CallWriter::enqueue (void)
221 {
222         DE_ASSERT(!m_enqueued);
223         m_queue->enqueue(m_call);
224         m_enqueued = true;
225 }
226
227 CallWriter& operator<< (CallWriter& writer, const char* str)
228 {
229         int pos = 0;
230         for (;;)
231         {
232                 writer.write((const deUint8*)str + pos, sizeof(char));
233                 if (str[pos] == 0)
234                         break;
235                 pos += 1;
236         }
237
238         return writer;
239 }
240
241 } // xe