renderer_utils.h (20412B)
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 <limits> 16 #include <map> 17 18 #include "GLSLANG/ShaderLang.h" 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 // The possible rotations of the surface/draw framebuffer, particularly for the Vulkan back-end on 48 // Android. 49 enum class SurfaceRotation 50 { 51 Identity, 52 Rotated90Degrees, 53 Rotated180Degrees, 54 Rotated270Degrees, 55 FlippedIdentity, 56 FlippedRotated90Degrees, 57 FlippedRotated180Degrees, 58 FlippedRotated270Degrees, 59 60 InvalidEnum, 61 EnumCount = InvalidEnum, 62 }; 63 64 bool IsRotatedAspectRatio(SurfaceRotation rotation); 65 66 using SpecConstUsageBits = angle::PackedEnumBitSet<sh::vk::SpecConstUsage, uint32_t>; 67 68 void RotateRectangle(const SurfaceRotation rotation, 69 const bool flipY, 70 const int framebufferWidth, 71 const int framebufferHeight, 72 const gl::Rectangle &incoming, 73 gl::Rectangle *outgoing); 74 75 using MipGenerationFunction = void (*)(size_t sourceWidth, 76 size_t sourceHeight, 77 size_t sourceDepth, 78 const uint8_t *sourceData, 79 size_t sourceRowPitch, 80 size_t sourceDepthPitch, 81 uint8_t *destData, 82 size_t destRowPitch, 83 size_t destDepthPitch); 84 85 typedef void (*PixelReadFunction)(const uint8_t *source, uint8_t *dest); 86 typedef void (*PixelWriteFunction)(const uint8_t *source, uint8_t *dest); 87 typedef void (*FastCopyFunction)(const uint8_t *source, 88 int srcXAxisPitch, 89 int srcYAxisPitch, 90 uint8_t *dest, 91 int destXAxisPitch, 92 int destYAxisPitch, 93 int width, 94 int height); 95 96 class FastCopyFunctionMap 97 { 98 public: 99 struct Entry 100 { 101 angle::FormatID formatID; 102 FastCopyFunction func; 103 }; 104 105 constexpr FastCopyFunctionMap() : FastCopyFunctionMap(nullptr, 0) {} 106 107 constexpr FastCopyFunctionMap(const Entry *data, size_t size) : mSize(size), mData(data) {} 108 109 bool has(angle::FormatID formatID) const; 110 FastCopyFunction get(angle::FormatID formatID) const; 111 112 private: 113 size_t mSize; 114 const Entry *mData; 115 }; 116 117 struct PackPixelsParams 118 { 119 PackPixelsParams(); 120 PackPixelsParams(const gl::Rectangle &area, 121 const angle::Format &destFormat, 122 GLuint outputPitch, 123 bool reverseRowOrderIn, 124 gl::Buffer *packBufferIn, 125 ptrdiff_t offset); 126 127 gl::Rectangle area; 128 const angle::Format *destFormat; 129 GLuint outputPitch; 130 gl::Buffer *packBuffer; 131 bool reverseRowOrder; 132 ptrdiff_t offset; 133 SurfaceRotation rotation; 134 }; 135 136 void PackPixels(const PackPixelsParams ¶ms, 137 const angle::Format &sourceFormat, 138 int inputPitch, 139 const uint8_t *source, 140 uint8_t *destination); 141 142 using InitializeTextureDataFunction = void (*)(size_t width, 143 size_t height, 144 size_t depth, 145 uint8_t *output, 146 size_t outputRowPitch, 147 size_t outputDepthPitch); 148 149 using LoadImageFunction = void (*)(size_t width, 150 size_t height, 151 size_t depth, 152 const uint8_t *input, 153 size_t inputRowPitch, 154 size_t inputDepthPitch, 155 uint8_t *output, 156 size_t outputRowPitch, 157 size_t outputDepthPitch); 158 159 struct LoadImageFunctionInfo 160 { 161 LoadImageFunctionInfo() : loadFunction(nullptr), requiresConversion(false) {} 162 LoadImageFunctionInfo(LoadImageFunction loadFunction, bool requiresConversion) 163 : loadFunction(loadFunction), requiresConversion(requiresConversion) 164 {} 165 166 LoadImageFunction loadFunction; 167 bool requiresConversion; 168 }; 169 170 using LoadFunctionMap = LoadImageFunctionInfo (*)(GLenum); 171 172 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs); 173 174 void CopyImageCHROMIUM(const uint8_t *sourceData, 175 size_t sourceRowPitch, 176 size_t sourcePixelBytes, 177 size_t sourceDepthPitch, 178 PixelReadFunction pixelReadFunction, 179 uint8_t *destData, 180 size_t destRowPitch, 181 size_t destPixelBytes, 182 size_t destDepthPitch, 183 PixelWriteFunction pixelWriteFunction, 184 GLenum destUnsizedFormat, 185 GLenum destComponentType, 186 size_t width, 187 size_t height, 188 size_t depth, 189 bool unpackFlipY, 190 bool unpackPremultiplyAlpha, 191 bool unpackUnmultiplyAlpha); 192 193 // Incomplete textures are 1x1 textures filled with black, used when samplers are incomplete. 194 // This helper class encapsulates handling incomplete textures. Because the GL back-end 195 // can take advantage of the driver's incomplete textures, and because clearing multisample 196 // textures is so difficult, we can keep an instance of this class in the back-end instead 197 // of moving the logic to the Context front-end. 198 199 // This interface allows us to call-back to init a multisample texture. 200 class MultisampleTextureInitializer 201 { 202 public: 203 virtual ~MultisampleTextureInitializer() {} 204 virtual angle::Result initializeMultisampleTextureToBlack(const gl::Context *context, 205 gl::Texture *glTexture) = 0; 206 }; 207 208 class IncompleteTextureSet final : angle::NonCopyable 209 { 210 public: 211 IncompleteTextureSet(); 212 ~IncompleteTextureSet(); 213 214 void onDestroy(const gl::Context *context); 215 216 angle::Result getIncompleteTexture(const gl::Context *context, 217 gl::TextureType type, 218 gl::SamplerFormat format, 219 MultisampleTextureInitializer *multisampleInitializer, 220 gl::Texture **textureOut); 221 222 private: 223 using TextureMapWithSamplerFormat = angle::PackedEnumMap<gl::SamplerFormat, gl::TextureMap>; 224 225 TextureMapWithSamplerFormat mIncompleteTextures; 226 gl::Buffer *mIncompleteTextureBufferAttachment; 227 }; 228 229 // Helpers to set a matrix uniform value based on GLSL or HLSL semantics. 230 // The return value indicate if the data was updated or not. 231 template <int cols, int rows> 232 struct SetFloatUniformMatrixGLSL 233 { 234 static void Run(unsigned int arrayElementOffset, 235 unsigned int elementCount, 236 GLsizei countIn, 237 GLboolean transpose, 238 const GLfloat *value, 239 uint8_t *targetData); 240 }; 241 242 template <int cols, int rows> 243 struct SetFloatUniformMatrixHLSL 244 { 245 static void Run(unsigned int arrayElementOffset, 246 unsigned int elementCount, 247 GLsizei countIn, 248 GLboolean transpose, 249 const GLfloat *value, 250 uint8_t *targetData); 251 }; 252 253 // Helper method to de-tranpose a matrix uniform for an API query. 254 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose); 255 256 template <typename NonFloatT> 257 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose); 258 259 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type); 260 261 angle::Result ComputeStartVertex(ContextImpl *contextImpl, 262 const gl::IndexRange &indexRange, 263 GLint baseVertex, 264 GLint *firstVertexOut); 265 266 angle::Result GetVertexRangeInfo(const gl::Context *context, 267 GLint firstVertex, 268 GLsizei vertexOrIndexCount, 269 gl::DrawElementsType indexTypeOrInvalid, 270 const void *indices, 271 GLint baseVertex, 272 GLint *startVertexOut, 273 size_t *vertexCountOut); 274 275 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY); 276 277 // Helper method to intialize a FeatureSet with overrides from the DisplayState 278 void ApplyFeatureOverrides(angle::FeatureSetBase *features, const egl::DisplayState &state); 279 280 template <typename In> 281 uint32_t LineLoopRestartIndexCountHelper(GLsizei indexCount, const uint8_t *srcPtr) 282 { 283 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>(); 284 const In *inIndices = reinterpret_cast<const In *>(srcPtr); 285 uint32_t numIndices = 0; 286 // See CopyLineLoopIndicesWithRestart() below for more info on how 287 // numIndices is calculated. 288 GLsizei loopStartIndex = 0; 289 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++) 290 { 291 In vertex = inIndices[curIndex]; 292 if (vertex != restartIndex) 293 { 294 numIndices++; 295 } 296 else 297 { 298 if (curIndex > loopStartIndex) 299 { 300 numIndices += 2; 301 } 302 loopStartIndex = curIndex + 1; 303 } 304 } 305 if (indexCount > loopStartIndex) 306 { 307 numIndices++; 308 } 309 return numIndices; 310 } 311 312 inline uint32_t GetLineLoopWithRestartIndexCount(gl::DrawElementsType glIndexType, 313 GLsizei indexCount, 314 const uint8_t *srcPtr) 315 { 316 switch (glIndexType) 317 { 318 case gl::DrawElementsType::UnsignedByte: 319 return LineLoopRestartIndexCountHelper<uint8_t>(indexCount, srcPtr); 320 case gl::DrawElementsType::UnsignedShort: 321 return LineLoopRestartIndexCountHelper<uint16_t>(indexCount, srcPtr); 322 case gl::DrawElementsType::UnsignedInt: 323 return LineLoopRestartIndexCountHelper<uint32_t>(indexCount, srcPtr); 324 default: 325 UNREACHABLE(); 326 return 0; 327 } 328 } 329 330 // Writes the line-strip vertices for a line loop to outPtr, 331 // where outLimit is calculated as in GetPrimitiveRestartIndexCount. 332 template <typename In, typename Out> 333 void CopyLineLoopIndicesWithRestart(GLsizei indexCount, const uint8_t *srcPtr, uint8_t *outPtr) 334 { 335 constexpr In restartIndex = gl::GetPrimitiveRestartIndexFromType<In>(); 336 constexpr Out outRestartIndex = gl::GetPrimitiveRestartIndexFromType<Out>(); 337 const In *inIndices = reinterpret_cast<const In *>(srcPtr); 338 Out *outIndices = reinterpret_cast<Out *>(outPtr); 339 GLsizei loopStartIndex = 0; 340 for (GLsizei curIndex = 0; curIndex < indexCount; curIndex++) 341 { 342 In vertex = inIndices[curIndex]; 343 if (vertex != restartIndex) 344 { 345 *(outIndices++) = static_cast<Out>(vertex); 346 } 347 else 348 { 349 if (curIndex > loopStartIndex) 350 { 351 // Emit an extra vertex only if the loop is not empty. 352 *(outIndices++) = inIndices[loopStartIndex]; 353 // Then restart the strip. 354 *(outIndices++) = outRestartIndex; 355 } 356 loopStartIndex = curIndex + 1; 357 } 358 } 359 if (indexCount > loopStartIndex) 360 { 361 // Close the last loop if not empty. 362 *(outIndices++) = inIndices[loopStartIndex]; 363 } 364 } 365 366 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy); 367 368 angle::Result MultiDrawArraysGeneral(ContextImpl *contextImpl, 369 const gl::Context *context, 370 gl::PrimitiveMode mode, 371 const GLint *firsts, 372 const GLsizei *counts, 373 GLsizei drawcount); 374 angle::Result MultiDrawArraysIndirectGeneral(ContextImpl *contextImpl, 375 const gl::Context *context, 376 gl::PrimitiveMode mode, 377 const void *indirect, 378 GLsizei drawcount, 379 GLsizei stride); 380 angle::Result MultiDrawArraysInstancedGeneral(ContextImpl *contextImpl, 381 const gl::Context *context, 382 gl::PrimitiveMode mode, 383 const GLint *firsts, 384 const GLsizei *counts, 385 const GLsizei *instanceCounts, 386 GLsizei drawcount); 387 angle::Result MultiDrawElementsGeneral(ContextImpl *contextImpl, 388 const gl::Context *context, 389 gl::PrimitiveMode mode, 390 const GLsizei *counts, 391 gl::DrawElementsType type, 392 const GLvoid *const *indices, 393 GLsizei drawcount); 394 angle::Result MultiDrawElementsIndirectGeneral(ContextImpl *contextImpl, 395 const gl::Context *context, 396 gl::PrimitiveMode mode, 397 gl::DrawElementsType type, 398 const void *indirect, 399 GLsizei drawcount, 400 GLsizei stride); 401 angle::Result MultiDrawElementsInstancedGeneral(ContextImpl *contextImpl, 402 const gl::Context *context, 403 gl::PrimitiveMode mode, 404 const GLsizei *counts, 405 gl::DrawElementsType type, 406 const GLvoid *const *indices, 407 const GLsizei *instanceCounts, 408 GLsizei drawcount); 409 angle::Result MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl *contextImpl, 410 const gl::Context *context, 411 gl::PrimitiveMode mode, 412 const GLint *firsts, 413 const GLsizei *counts, 414 const GLsizei *instanceCounts, 415 const GLuint *baseInstances, 416 GLsizei drawcount); 417 angle::Result MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl *contextImpl, 418 const gl::Context *context, 419 gl::PrimitiveMode mode, 420 const GLsizei *counts, 421 gl::DrawElementsType type, 422 const GLvoid *const *indices, 423 const GLsizei *instanceCounts, 424 const GLint *baseVertices, 425 const GLuint *baseInstances, 426 GLsizei drawcount); 427 428 // RAII object making sure reset uniforms is called no matter whether there's an error in draw calls 429 class ResetBaseVertexBaseInstance : angle::NonCopyable 430 { 431 public: 432 ResetBaseVertexBaseInstance(gl::Program *programObject, 433 bool resetBaseVertex, 434 bool resetBaseInstance); 435 436 ~ResetBaseVertexBaseInstance(); 437 438 private: 439 gl::Program *mProgramObject; 440 bool mResetBaseVertex; 441 bool mResetBaseInstance; 442 }; 443 444 angle::FormatID ConvertToSRGB(angle::FormatID formatID); 445 angle::FormatID ConvertToLinear(angle::FormatID formatID); 446 bool IsOverridableLinearFormat(angle::FormatID formatID); 447 448 enum class PipelineType 449 { 450 Graphics = 0, 451 Compute = 1, 452 453 InvalidEnum = 2, 454 EnumCount = 2, 455 }; 456 } // namespace rx 457 458 // MultiDraw macro patterns 459 // These macros are to avoid too much code duplication as we don't want to have if detect for 460 // hasDrawID/BaseVertex/BaseInstance inside for loop in a multiDrawANGLE call Part of these are put 461 // in the header as we want to share with specialized context impl on some platforms for multidraw 462 #define ANGLE_SET_DRAW_ID_UNIFORM_0(drawID) \ 463 {} 464 #define ANGLE_SET_DRAW_ID_UNIFORM_1(drawID) programObject->setDrawIDUniform(drawID) 465 #define ANGLE_SET_DRAW_ID_UNIFORM(cond) ANGLE_SET_DRAW_ID_UNIFORM_##cond 466 467 #define ANGLE_SET_BASE_VERTEX_UNIFORM_0(baseVertex) \ 468 {} 469 #define ANGLE_SET_BASE_VERTEX_UNIFORM_1(baseVertex) programObject->setBaseVertexUniform(baseVertex); 470 #define ANGLE_SET_BASE_VERTEX_UNIFORM(cond) ANGLE_SET_BASE_VERTEX_UNIFORM_##cond 471 472 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_0(baseInstance) \ 473 {} 474 #define ANGLE_SET_BASE_INSTANCE_UNIFORM_1(baseInstance) \ 475 programObject->setBaseInstanceUniform(baseInstance) 476 #define ANGLE_SET_BASE_INSTANCE_UNIFORM(cond) ANGLE_SET_BASE_INSTANCE_UNIFORM_##cond 477 478 #define ANGLE_NOOP_DRAW_ context->noopDraw(mode, counts[drawID]) 479 #define ANGLE_NOOP_DRAW_INSTANCED \ 480 context->noopDrawInstanced(mode, counts[drawID], instanceCounts[drawID]) 481 #define ANGLE_NOOP_DRAW(_instanced) ANGLE_NOOP_DRAW##_instanced 482 483 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_ \ 484 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], 1) 485 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE_INSTANCED \ 486 gl::MarkTransformFeedbackBufferUsage(context, counts[drawID], instanceCounts[drawID]) 487 #define ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced) \ 488 ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE##instanced 489 490 // Helper macro that casts to a bitfield type then verifies no bits were dropped. 491 #define SetBitField(lhs, rhs) \ 492 do \ 493 { \ 494 auto ANGLE_LOCAL_VAR = rhs; \ 495 lhs = static_cast<typename std::decay<decltype(lhs)>::type>(ANGLE_LOCAL_VAR); \ 496 ASSERT(static_cast<decltype(ANGLE_LOCAL_VAR)>(lhs) == ANGLE_LOCAL_VAR); \ 497 } while (0) 498 499 #endif // LIBANGLE_RENDERER_RENDERER_UTILS_H_