1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // renderer_utils:
7 // Helper methods pertaining to most or all back-ends.
8 //
9
10 #ifndef LIBANGLE_RENDERER_RENDERER_UTILS_H_
11 #define LIBANGLE_RENDERER_RENDERER_UTILS_H_
12
13 #include <cstdint>
14
15 #include <atomic>
16 #include <limits>
17 #include <map>
18
19 #include "common/angleutils.h"
20 #include "common/utilities.h"
21 #include "libANGLE/angletypes.h"
22
23 namespace angle
24 {
25 struct FeatureSetBase;
26 struct Format;
27 enum class FormatID;
28 } // namespace angle
29
30 namespace gl
31 {
32 struct FormatType;
33 struct InternalFormat;
34 class State;
35 } // namespace gl
36
37 namespace egl
38 {
39 class AttributeMap;
40 struct DisplayState;
41 } // namespace egl
42
43 namespace rx
44 {
45 class ContextImpl;
46
47 class ResourceSerial
48 {
49 public:
ResourceSerial()50 constexpr ResourceSerial() : mValue(kDirty) {}
ResourceSerial(uintptr_t value)51 explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {}
52 constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; }
53 constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; }
54
dirty()55 void dirty() { mValue = kDirty; }
clear()56 void clear() { mValue = kEmpty; }
57
valid()58 constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; }
empty()59 constexpr bool empty() const { return mValue == kEmpty; }
60
61 private:
62 constexpr static uintptr_t kDirty = std::numeric_limits<uintptr_t>::max();
63 constexpr static uintptr_t kEmpty = 0;
64
65 uintptr_t mValue;
66 };
67
68 class Serial final
69 {
70 public:
Serial()71 constexpr Serial() : mValue(kInvalid) {}
72 constexpr Serial(const Serial &other) = default;
73 Serial &operator=(const Serial &other) = default;
74
75 constexpr bool operator==(const Serial &other) const
76 {
77 return mValue != kInvalid && mValue == other.mValue;
78 }
79 constexpr bool operator==(uint32_t value) const
80 {
81 return mValue != kInvalid && mValue == static_cast<uint64_t>(value);
82 }
83 constexpr bool operator!=(const Serial &other) const
84 {
85 return mValue == kInvalid || mValue != other.mValue;
86 }
87 constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; }
88 constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; }
89 constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; }
90 constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; }
91
92 constexpr bool operator<(uint32_t value) const { return mValue < static_cast<uint64_t>(value); }
93
94 // Useful for serialization.
getValue()95 constexpr uint64_t getValue() const { return mValue; }
96
97 private:
98 template <typename T>
99 friend class SerialFactoryBase;
Serial(uint64_t value)100 constexpr explicit Serial(uint64_t value) : mValue(value) {}
101 uint64_t mValue;
102 static constexpr uint64_t kInvalid = 0;
103 };
104
105 template <typename SerialBaseType>
106 class SerialFactoryBase final : angle::NonCopyable
107 {
108 public:
SerialFactoryBase()109 SerialFactoryBase() : mSerial(1) {}
110
generate()111 Serial generate()
112 {
113 ASSERT(mSerial + 1 > mSerial);
114 return Serial(mSerial++);
115 }
116
117 private:
118 SerialBaseType mSerial;
119 };
120
121 using SerialFactory = SerialFactoryBase<uint64_t>;
122 using AtomicSerialFactory = SerialFactoryBase<std::atomic<uint64_t>>;
123
124 using MipGenerationFunction = void (*)(size_t sourceWidth,
125 size_t sourceHeight,
126 size_t sourceDepth,
127 const uint8_t *sourceData,
128 size_t sourceRowPitch,
129 size_t sourceDepthPitch,
130 uint8_t *destData,
131 size_t destRowPitch,
132 size_t destDepthPitch);
133
134 typedef void (*PixelReadFunction)(const uint8_t *source, uint8_t *dest);
135 typedef void (*PixelWriteFunction)(const uint8_t *source, uint8_t *dest);
136 typedef void (*PixelCopyFunction)(const uint8_t *source, uint8_t *dest);
137
138 class FastCopyFunctionMap
139 {
140 public:
141 struct Entry
142 {
143 angle::FormatID formatID;
144 PixelCopyFunction func;
145 };
146
FastCopyFunctionMap()147 constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {}
148
FastCopyFunctionMap(const Entry * data,size_t size)149 constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {}
150
151 bool has(angle::FormatID formatID) const;
152 PixelCopyFunction get(angle::FormatID formatID) const;
153
154 private:
155 size_t mSize;
156 const Entry *mData;
157 };
158
159 struct PackPixelsParams
160 {
161 PackPixelsParams();
162 PackPixelsParams(const gl::Rectangle &area,
163 const angle::Format &destFormat,
164 GLuint outputPitch,
165 bool reverseRowOrderIn,
166 gl::Buffer *packBufferIn,
167 ptrdiff_t offset);
168
169 gl::Rectangle area;
170 const angle::Format *destFormat;
171 GLuint outputPitch;
172 gl::Buffer *packBuffer;
173 bool reverseRowOrder;
174 ptrdiff_t offset;
175 };
176
177 void PackPixels(const PackPixelsParams ¶ms,
178 const angle::Format &sourceFormat,
179 int inputPitch,
180 const uint8_t *source,
181 uint8_t *destination);
182
183 using InitializeTextureDataFunction = void (*)(size_t width,
184 size_t height,
185 size_t depth,
186 uint8_t *output,
187 size_t outputRowPitch,
188 size_t outputDepthPitch);
189
190 using LoadImageFunction = void (*)(size_t width,
191 size_t height,
192 size_t depth,
193 const uint8_t *input,
194 size_t inputRowPitch,
195 size_t inputDepthPitch,
196 uint8_t *output,
197 size_t outputRowPitch,
198 size_t outputDepthPitch);
199
200 struct LoadImageFunctionInfo
201 {
LoadImageFunctionInfoLoadImageFunctionInfo202 LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {}
LoadImageFunctionInfoLoadImageFunctionInfo203 LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion)
204 : loadFunction(loadFunction), requiresConversion(requiresConversion)
205 {}
206
207 LoadImageFunction loadFunction;
208 bool requiresConversion;
209 };
210
211 using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum);
212
213 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs);
214 bool ShouldUseVirtualizedContexts(const egl::AttributeMap &attribs, bool defaultValue);
215
216 void CopyImageCHROMIUM(const uint8_t *sourceData,
217 size_t sourceRowPitch,
218 size_t sourcePixelBytes,
219 size_t sourceDepthPitch,
220 PixelReadFunction pixelReadFunction,
221 uint8_t *destData,
222 size_t destRowPitch,
223 size_t destPixelBytes,
224 size_t destDepthPitch,
225 PixelWriteFunction pixelWriteFunction,
226 GLenum destUnsizedFormat,
227 GLenum destComponentType,
228 size_t width,
229 size_t height,
230 size_t depth,
231 bool unpackFlipY,
232 bool unpackPremultiplyAlpha,
233 bool unpackUnmultiplyAlpha);
234
235 // Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete.
236 // This helper class encapsulates handling incomplete textures. Because the GL back-end
237 // can take advantage of the driver's incomplete textures, and because clearing multisample
238 // textures is so difficult, we can keep an instance of this class in the back-end instead
239 // of moving the logic to the Context front-end.
240
241 // This interface allows us to call-back to init a multisample texture.
242 class MultisampleTextureInitializer
243 {
244 public:
~MultisampleTextureInitializer()245 virtual ~MultisampleTextureInitializer() {}
246 virtual angle::Result initializeMultisampleTextureToBlack(const gl::Context *context,
247 gl::Texture *glTexture) = 0;
248 };
249
250 class IncompleteTextureSet final : angle::NonCopyable
251 {
252 public:
253 IncompleteTextureSet();
254 ~IncompleteTextureSet();
255
256 void onDestroy(const gl::Context *context);
257
258 angle::Result getIncompleteTexture(const gl::Context *context,
259 gl::TextureType type,
260 MultisampleTextureInitializer *multisampleInitializer,
261 gl::Texture **textureOut);
262
263 private:
264 gl::TextureMap mIncompleteTextures;
265 };
266
267 // Helpers to set a matrix uniform value based on GLSL or HLSL semantics.
268 // The return value indicate if the data was updated or not.
269 template <int cols, int rows>
270 struct SetFloatUniformMatrixGLSL
271 {
272 static void Run(unsigned int arrayElementOffset,
273 unsigned int elementCount,
274 GLsizei countIn,
275 GLboolean transpose,
276 const GLfloat *value,
277 uint8_t *targetData);
278 };
279
280 template <int cols, int rows>
281 struct SetFloatUniformMatrixHLSL
282 {
283 static void Run(unsigned int arrayElementOffset,
284 unsigned int elementCount,
285 GLsizei countIn,
286 GLboolean transpose,
287 const GLfloat *value,
288 uint8_t *targetData);
289 };
290
291 // Helper method to de-tranpose a matrix uniform for an API query.
292 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose);
293
294 template <typename NonFloatT>
295 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose);
296
297 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type);
298
299 angle::Result ComputeStartVertex(ContextImpl *contextImpl,
300 const gl::IndexRange &indexRange,
301 GLint baseVertex,
302 GLint *firstVertexOut);
303
304 angle::Result GetVertexRangeInfo(const gl::Context *context,
305 GLint firstVertex,
306 GLsizei vertexOrIndexCount,
307 gl::DrawElementsType indexTypeOrInvalid,
308 const void *indices,
309 GLint baseVertex,
310 GLint *startVertexOut,
311 size_t *vertexCountOut);
312
313 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY);
314
315 // Helper method to intialize a FeatureSet with overrides from the DisplayState
316 void OverrideFeaturesWithDisplayState(angle::FeatureSetBase *features,
317 const egl::DisplayState &state);
318
319 template <typename In>
LineLoopRestartIndexCountHelper(GLsizei indexCount,const uint8_t * srcPtr)320 uint32_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr)
321 {
322 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
323 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
324 uint32_t numIndices = 0;
325 // See CopyLineLoopIndicesWithRestart() below for more info on how
326 // numIndices is calculated.
327 GLsizei loopStartIndex = 0;
328 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
329 {
330 In vertex = inIndices[curIndex];
331 if (vertex != restartIndex)
332 {
333 numIndices++;
334 }
335 else
336 {
337 if (curIndex > loopStartIndex)
338 {
339 numIndices += 2;
340 }
341 loopStartIndex = curIndex + 1;
342 }
343 }
344 if (indexCount > loopStartIndex)
345 {
346 numIndices++;
347 }
348 return numIndices;
349 }
350
GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr)351 inline uint32_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType,
352 GLsizei indexCount,
353 const uint8_t *srcPtr)
354 {
355 switch (glIndexType)
356 {
357 case gl::DrawElementsType::UnsignedByte:
358 return LineLoopRestartIndexCountHelper<uint8_t>(indexCount, srcPtr);
359 case gl::DrawElementsType::UnsignedShort:
360 return LineLoopRestartIndexCountHelper<uint16_t>(indexCount, srcPtr);
361 case gl::DrawElementsType::UnsignedInt:
362 return LineLoopRestartIndexCountHelper<uint32_t>(indexCount, srcPtr);
363 default:
364 UNREACHABLE();
365 return 0;
366 }
367 }
368
369 // Writes the line-strip vertices for a line loop to outPtr,
370 // where outLimit is calculated as in GetPrimitiveRestartIndexCount.
371 template <typename In, typename Out>
CopyLineLoopIndicesWithRestart(GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)372 void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr)
373 {
374 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>();
375 constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType<Out>();
376 const In *inIndices = reinterpret_cast<const In *>(srcPtr);
377 Out *outIndices = reinterpret_cast<Out *>(outPtr);
378 GLsizei loopStartIndex = 0;
379 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++)
380 {
381 In vertex = inIndices[curIndex];
382 if (vertex != restartIndex)
383 {
384 *(outIndices++) = static_cast<Out>(vertex);
385 }
386 else
387 {
388 if (curIndex > loopStartIndex)
389 {
390 // Emit an extra vertex only if the loop is not empty.
391 *(outIndices++) = inIndices[loopStartIndex];
392 // Then restart the strip.
393 *(outIndices++) = outRestartIndex;
394 }
395 loopStartIndex = curIndex + 1;
396 }
397 }
398 if (indexCount > loopStartIndex)
399 {
400 // Close the last loop if not empty.
401 *(outIndices++) = inIndices[loopStartIndex];
402 }
403 }
404 } // namespace rx
405
406 #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_
407