renderer_utils.cpp (62537B)
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 #include "libANGLE/renderer/renderer_utils.h" 11 12 #include "common/string_utils.h" 13 #include "common/system_utils.h" 14 #include "common/utilities.h" 15 #include "image_util/copyimage.h" 16 #include "image_util/imageformats.h" 17 #include "libANGLE/AttributeMap.h" 18 #include "libANGLE/Context.h" 19 #include "libANGLE/Context.inl.h" 20 #include "libANGLE/Display.h" 21 #include "libANGLE/formatutils.h" 22 #include "libANGLE/renderer/ContextImpl.h" 23 #include "libANGLE/renderer/Format.h" 24 #include "platform/Feature.h" 25 26 #include <string.h> 27 #include <cctype> 28 29 namespace angle 30 { 31 namespace 32 { 33 // For the sake of feature name matching, underscore is ignored, and the names are matched 34 // case-insensitive. This allows feature names to be overriden both in snake_case (previously used 35 // by ANGLE) and camelCase. The second string (user-provided name) can end in `*` for wildcard 36 // matching. 37 bool FeatureNameMatch(const std::string &a, const std::string &b) 38 { 39 size_t ai = 0; 40 size_t bi = 0; 41 42 while (ai < a.size() && bi < b.size()) 43 { 44 if (a[ai] == '_') 45 { 46 ++ai; 47 } 48 if (b[bi] == '_') 49 { 50 ++bi; 51 } 52 if (b[bi] == '*' && bi + 1 == b.size()) 53 { 54 // If selected feature name ends in wildcard, match it. 55 return true; 56 } 57 if (std::tolower(a[ai++]) != std::tolower(b[bi++])) 58 { 59 return false; 60 } 61 } 62 63 return ai == a.size() && bi == b.size(); 64 } 65 } // anonymous namespace 66 67 // FeatureSetBase implementation 68 void FeatureSetBase::overrideFeatures(const std::vector<std::string> &featureNames, bool enabled) 69 { 70 for (const std::string &name : featureNames) 71 { 72 const bool hasWildcard = name.back() == '*'; 73 for (auto iter : members) 74 { 75 const std::string &featureName = iter.first; 76 FeatureInfo *feature = iter.second; 77 78 if (!FeatureNameMatch(featureName, name)) 79 { 80 continue; 81 } 82 83 feature->enabled = enabled; 84 85 // If name has a wildcard, try to match it with all features. Otherwise, bail on first 86 // match, as names are unique. 87 if (!hasWildcard) 88 { 89 break; 90 } 91 } 92 } 93 } 94 95 void FeatureSetBase::populateFeatureList(FeatureList *features) const 96 { 97 for (FeatureMap::const_iterator it = members.begin(); it != members.end(); it++) 98 { 99 features->push_back(it->second); 100 } 101 } 102 } // namespace angle 103 104 namespace rx 105 { 106 107 namespace 108 { 109 // Both D3D and Vulkan support the same set of standard sample positions for 1, 2, 4, 8, and 16 110 // samples. See: 111 // 112 // - https://msdn.microsoft.com/en-us/library/windows/desktop/ff476218.aspx 113 // 114 // - 115 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#primsrast-multisampling 116 using SamplePositionsArray = std::array<float, 32>; 117 constexpr std::array<SamplePositionsArray, 5> kSamplePositions = { 118 {{{0.5f, 0.5f}}, 119 {{0.75f, 0.75f, 0.25f, 0.25f}}, 120 {{0.375f, 0.125f, 0.875f, 0.375f, 0.125f, 0.625f, 0.625f, 0.875f}}, 121 {{0.5625f, 0.3125f, 0.4375f, 0.6875f, 0.8125f, 0.5625f, 0.3125f, 0.1875f, 0.1875f, 0.8125f, 122 0.0625f, 0.4375f, 0.6875f, 0.9375f, 0.9375f, 0.0625f}}, 123 {{0.5625f, 0.5625f, 0.4375f, 0.3125f, 0.3125f, 0.625f, 0.75f, 0.4375f, 124 0.1875f, 0.375f, 0.625f, 0.8125f, 0.8125f, 0.6875f, 0.6875f, 0.1875f, 125 0.375f, 0.875f, 0.5f, 0.0625f, 0.25f, 0.125f, 0.125f, 0.75f, 126 0.0f, 0.5f, 0.9375f, 0.25f, 0.875f, 0.9375f, 0.0625f, 0.0f}}}}; 127 128 struct IncompleteTextureParameters 129 { 130 GLenum sizedInternalFormat; 131 GLenum format; 132 GLenum type; 133 GLubyte clearColor[4]; 134 }; 135 136 // Note that for gl::SamplerFormat::Shadow, the clearColor datatype needs to be GLushort and as such 137 // we will reinterpret GLubyte[4] as GLushort[2]. 138 constexpr angle::PackedEnumMap<gl::SamplerFormat, IncompleteTextureParameters> 139 kIncompleteTextureParameters = { 140 {gl::SamplerFormat::Float, {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, {0, 0, 0, 255}}}, 141 {gl::SamplerFormat::Unsigned, 142 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, {0, 0, 0, 255}}}, 143 {gl::SamplerFormat::Signed, {GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, {0, 0, 0, 127}}}, 144 {gl::SamplerFormat::Shadow, 145 {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, {0, 0, 0, 0}}}}; 146 147 void CopyColor(gl::ColorF *color) 148 { 149 // No-op 150 } 151 152 void PremultiplyAlpha(gl::ColorF *color) 153 { 154 color->red *= color->alpha; 155 color->green *= color->alpha; 156 color->blue *= color->alpha; 157 } 158 159 void UnmultiplyAlpha(gl::ColorF *color) 160 { 161 if (color->alpha != 0.0f) 162 { 163 float invAlpha = 1.0f / color->alpha; 164 color->red *= invAlpha; 165 color->green *= invAlpha; 166 color->blue *= invAlpha; 167 } 168 } 169 170 void ClipChannelsR(gl::ColorF *color) 171 { 172 color->green = 0.0f; 173 color->blue = 0.0f; 174 color->alpha = 1.0f; 175 } 176 177 void ClipChannelsRG(gl::ColorF *color) 178 { 179 color->blue = 0.0f; 180 color->alpha = 1.0f; 181 } 182 183 void ClipChannelsRGB(gl::ColorF *color) 184 { 185 color->alpha = 1.0f; 186 } 187 188 void ClipChannelsLuminance(gl::ColorF *color) 189 { 190 color->alpha = 1.0f; 191 } 192 193 void ClipChannelsAlpha(gl::ColorF *color) 194 { 195 color->red = 0.0f; 196 color->green = 0.0f; 197 color->blue = 0.0f; 198 } 199 200 void ClipChannelsNoOp(gl::ColorF *color) {} 201 202 void WriteUintColor(const gl::ColorF &color, 203 PixelWriteFunction colorWriteFunction, 204 uint8_t *destPixelData) 205 { 206 gl::ColorUI destColor( 207 static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.green * 255), 208 static_cast<unsigned int>(color.blue * 255), static_cast<unsigned int>(color.alpha * 255)); 209 colorWriteFunction(reinterpret_cast<const uint8_t *>(&destColor), destPixelData); 210 } 211 212 void WriteFloatColor(const gl::ColorF &color, 213 PixelWriteFunction colorWriteFunction, 214 uint8_t *destPixelData) 215 { 216 colorWriteFunction(reinterpret_cast<const uint8_t *>(&color), destPixelData); 217 } 218 219 template <int cols, int rows, bool IsColumnMajor> 220 inline int GetFlattenedIndex(int col, int row) 221 { 222 if (IsColumnMajor) 223 { 224 return col * rows + row; 225 } 226 else 227 { 228 return row * cols + col; 229 } 230 } 231 232 template <typename T, 233 bool IsSrcColumnMajor, 234 int colsSrc, 235 int rowsSrc, 236 bool IsDstColumnMajor, 237 int colsDst, 238 int rowsDst> 239 void ExpandMatrix(T *target, const GLfloat *value) 240 { 241 static_assert(colsSrc <= colsDst && rowsSrc <= rowsDst, "Can only expand!"); 242 243 constexpr int kDstFlatSize = colsDst * rowsDst; 244 T staging[kDstFlatSize] = {0}; 245 246 for (int r = 0; r < rowsSrc; r++) 247 { 248 for (int c = 0; c < colsSrc; c++) 249 { 250 int srcIndex = GetFlattenedIndex<colsSrc, rowsSrc, IsSrcColumnMajor>(c, r); 251 int dstIndex = GetFlattenedIndex<colsDst, rowsDst, IsDstColumnMajor>(c, r); 252 253 staging[dstIndex] = static_cast<T>(value[srcIndex]); 254 } 255 } 256 257 memcpy(target, staging, kDstFlatSize * sizeof(T)); 258 } 259 260 template <bool IsSrcColumMajor, 261 int colsSrc, 262 int rowsSrc, 263 bool IsDstColumnMajor, 264 int colsDst, 265 int rowsDst> 266 void SetFloatUniformMatrix(unsigned int arrayElementOffset, 267 unsigned int elementCount, 268 GLsizei countIn, 269 const GLfloat *value, 270 uint8_t *targetData) 271 { 272 unsigned int count = 273 std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn)); 274 275 const unsigned int targetMatrixStride = colsDst * rowsDst; 276 GLfloat *target = reinterpret_cast<GLfloat *>( 277 targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride); 278 279 for (unsigned int i = 0; i < count; i++) 280 { 281 ExpandMatrix<GLfloat, IsSrcColumMajor, colsSrc, rowsSrc, IsDstColumnMajor, colsDst, 282 rowsDst>(target, value); 283 284 target += targetMatrixStride; 285 value += colsSrc * rowsSrc; 286 } 287 } 288 289 void SetFloatUniformMatrixFast(unsigned int arrayElementOffset, 290 unsigned int elementCount, 291 GLsizei countIn, 292 size_t matrixSize, 293 const GLfloat *value, 294 uint8_t *targetData) 295 { 296 const unsigned int count = 297 std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn)); 298 299 const uint8_t *valueData = reinterpret_cast<const uint8_t *>(value); 300 targetData = targetData + arrayElementOffset * matrixSize; 301 302 memcpy(targetData, valueData, matrixSize * count); 303 } 304 } // anonymous namespace 305 306 bool IsRotatedAspectRatio(SurfaceRotation rotation) 307 { 308 switch (rotation) 309 { 310 case SurfaceRotation::Rotated90Degrees: 311 case SurfaceRotation::Rotated270Degrees: 312 case SurfaceRotation::FlippedRotated90Degrees: 313 case SurfaceRotation::FlippedRotated270Degrees: 314 return true; 315 default: 316 return false; 317 } 318 } 319 320 void RotateRectangle(const SurfaceRotation rotation, 321 const bool flipY, 322 const int framebufferWidth, 323 const int framebufferHeight, 324 const gl::Rectangle &incoming, 325 gl::Rectangle *outgoing) 326 { 327 // GLES's y-axis points up; Vulkan's points down. 328 switch (rotation) 329 { 330 case SurfaceRotation::Identity: 331 // Do not rotate gl_Position (surface matches the device's orientation): 332 outgoing->x = incoming.x; 333 outgoing->y = flipY ? framebufferHeight - incoming.y - incoming.height : incoming.y; 334 outgoing->width = incoming.width; 335 outgoing->height = incoming.height; 336 break; 337 case SurfaceRotation::Rotated90Degrees: 338 // Rotate gl_Position 90 degrees: 339 outgoing->x = incoming.y; 340 outgoing->y = flipY ? incoming.x : framebufferWidth - incoming.x - incoming.width; 341 outgoing->width = incoming.height; 342 outgoing->height = incoming.width; 343 break; 344 case SurfaceRotation::Rotated180Degrees: 345 // Rotate gl_Position 180 degrees: 346 outgoing->x = framebufferWidth - incoming.x - incoming.width; 347 outgoing->y = flipY ? incoming.y : framebufferHeight - incoming.y - incoming.height; 348 outgoing->width = incoming.width; 349 outgoing->height = incoming.height; 350 break; 351 case SurfaceRotation::Rotated270Degrees: 352 // Rotate gl_Position 270 degrees: 353 outgoing->x = framebufferHeight - incoming.y - incoming.height; 354 outgoing->y = flipY ? framebufferWidth - incoming.x - incoming.width : incoming.x; 355 outgoing->width = incoming.height; 356 outgoing->height = incoming.width; 357 break; 358 default: 359 UNREACHABLE(); 360 break; 361 } 362 } 363 364 PackPixelsParams::PackPixelsParams() 365 : destFormat(nullptr), 366 outputPitch(0), 367 packBuffer(nullptr), 368 offset(0), 369 rotation(SurfaceRotation::Identity) 370 {} 371 372 PackPixelsParams::PackPixelsParams(const gl::Rectangle &areaIn, 373 const angle::Format &destFormat, 374 GLuint outputPitchIn, 375 bool reverseRowOrderIn, 376 gl::Buffer *packBufferIn, 377 ptrdiff_t offsetIn) 378 : area(areaIn), 379 destFormat(&destFormat), 380 outputPitch(outputPitchIn), 381 packBuffer(packBufferIn), 382 reverseRowOrder(reverseRowOrderIn), 383 offset(offsetIn), 384 rotation(SurfaceRotation::Identity) 385 {} 386 387 void PackPixels(const PackPixelsParams ¶ms, 388 const angle::Format &sourceFormat, 389 int inputPitchIn, 390 const uint8_t *sourceIn, 391 uint8_t *destWithoutOffset) 392 { 393 uint8_t *destWithOffset = destWithoutOffset + params.offset; 394 395 const uint8_t *source = sourceIn; 396 int inputPitch = inputPitchIn; 397 int destWidth = params.area.width; 398 int destHeight = params.area.height; 399 int xAxisPitch = 0; 400 int yAxisPitch = 0; 401 switch (params.rotation) 402 { 403 case SurfaceRotation::Identity: 404 // The source image is not rotated (i.e. matches the device's orientation), and may or 405 // may not be y-flipped. The image is row-major. Each source row (one step along the 406 // y-axis for each step in the dest y-axis) is inputPitch past the previous row. Along 407 // a row, each source pixel (one step along the x-axis for each step in the dest 408 // x-axis) is sourceFormat.pixelBytes past the previous pixel. 409 xAxisPitch = sourceFormat.pixelBytes; 410 if (params.reverseRowOrder) 411 { 412 // The source image is y-flipped, which means we start at the last row, and each 413 // source row is BEFORE the previous row. 414 source += inputPitchIn * (params.area.height - 1); 415 inputPitch = -inputPitch; 416 yAxisPitch = -inputPitchIn; 417 } 418 else 419 { 420 yAxisPitch = inputPitchIn; 421 } 422 break; 423 case SurfaceRotation::Rotated90Degrees: 424 // The source image is rotated 90 degrees counter-clockwise. Y-flip is always applied 425 // to rotated images. The image is column-major. Each source column (one step along 426 // the source x-axis for each step in the dest y-axis) is inputPitch past the previous 427 // column. Along a column, each source pixel (one step along the y-axis for each step 428 // in the dest x-axis) is sourceFormat.pixelBytes past the previous pixel. 429 xAxisPitch = inputPitchIn; 430 yAxisPitch = sourceFormat.pixelBytes; 431 destWidth = params.area.height; 432 destHeight = params.area.width; 433 break; 434 case SurfaceRotation::Rotated180Degrees: 435 // The source image is rotated 180 degrees. Y-flip is always applied to rotated 436 // images. The image is row-major, but upside down. Each source row (one step along 437 // the y-axis for each step in the dest y-axis) is inputPitch after the previous row. 438 // Along a row, each source pixel (one step along the x-axis for each step in the dest 439 // x-axis) is sourceFormat.pixelBytes BEFORE the previous pixel. 440 xAxisPitch = -static_cast<int>(sourceFormat.pixelBytes); 441 yAxisPitch = inputPitchIn; 442 source += sourceFormat.pixelBytes * (params.area.width - 1); 443 break; 444 case SurfaceRotation::Rotated270Degrees: 445 // The source image is rotated 270 degrees counter-clockwise (or 90 degrees clockwise). 446 // Y-flip is always applied to rotated images. The image is column-major, where each 447 // column (one step in the source x-axis for one step in the dest y-axis) is inputPitch 448 // BEFORE the previous column. Along a column, each source pixel (one step along the 449 // y-axis for each step in the dest x-axis) is sourceFormat.pixelBytes BEFORE the 450 // previous pixel. The first pixel is at the end of the source. 451 xAxisPitch = -inputPitchIn; 452 yAxisPitch = -static_cast<int>(sourceFormat.pixelBytes); 453 destWidth = params.area.height; 454 destHeight = params.area.width; 455 source += inputPitch * (params.area.height - 1) + 456 sourceFormat.pixelBytes * (params.area.width - 1); 457 break; 458 default: 459 UNREACHABLE(); 460 break; 461 } 462 463 if (params.rotation == SurfaceRotation::Identity && sourceFormat == *params.destFormat) 464 { 465 // Direct copy possible 466 for (int y = 0; y < params.area.height; ++y) 467 { 468 memcpy(destWithOffset + y * params.outputPitch, source + y * inputPitch, 469 params.area.width * sourceFormat.pixelBytes); 470 } 471 return; 472 } 473 474 FastCopyFunction fastCopyFunc = sourceFormat.fastCopyFunctions.get(params.destFormat->id); 475 476 if (fastCopyFunc) 477 { 478 // Fast copy is possible through some special function 479 fastCopyFunc(source, xAxisPitch, yAxisPitch, destWithOffset, params.destFormat->pixelBytes, 480 params.outputPitch, destWidth, destHeight); 481 return; 482 } 483 484 PixelWriteFunction pixelWriteFunction = params.destFormat->pixelWriteFunction; 485 ASSERT(pixelWriteFunction != nullptr); 486 487 // Maximum size of any Color<T> type used. 488 uint8_t temp[16]; 489 static_assert(sizeof(temp) >= sizeof(gl::ColorF) && sizeof(temp) >= sizeof(gl::ColorUI) && 490 sizeof(temp) >= sizeof(gl::ColorI) && 491 sizeof(temp) >= sizeof(angle::DepthStencil), 492 "Unexpected size of pixel struct."); 493 494 PixelReadFunction pixelReadFunction = sourceFormat.pixelReadFunction; 495 ASSERT(pixelReadFunction != nullptr); 496 497 for (int y = 0; y < destHeight; ++y) 498 { 499 for (int x = 0; x < destWidth; ++x) 500 { 501 uint8_t *dest = 502 destWithOffset + y * params.outputPitch + x * params.destFormat->pixelBytes; 503 const uint8_t *src = source + y * yAxisPitch + x * xAxisPitch; 504 505 // readFunc and writeFunc will be using the same type of color, CopyTexImage 506 // will not allow the copy otherwise. 507 pixelReadFunction(src, temp); 508 pixelWriteFunction(temp, dest); 509 } 510 } 511 } 512 513 bool FastCopyFunctionMap::has(angle::FormatID formatID) const 514 { 515 return (get(formatID) != nullptr); 516 } 517 518 namespace 519 { 520 521 const FastCopyFunctionMap::Entry *getEntry(const FastCopyFunctionMap::Entry *entry, 522 size_t numEntries, 523 angle::FormatID formatID) 524 { 525 const FastCopyFunctionMap::Entry *end = entry + numEntries; 526 while (entry != end) 527 { 528 if (entry->formatID == formatID) 529 { 530 return entry; 531 } 532 ++entry; 533 } 534 535 return nullptr; 536 } 537 538 } // namespace 539 540 FastCopyFunction FastCopyFunctionMap::get(angle::FormatID formatID) const 541 { 542 const FastCopyFunctionMap::Entry *entry = getEntry(mData, mSize, formatID); 543 return entry ? entry->func : nullptr; 544 } 545 546 bool ShouldUseDebugLayers(const egl::AttributeMap &attribs) 547 { 548 EGLAttrib debugSetting = 549 attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); 550 551 // Prefer to enable debug layers when available. 552 #if defined(ANGLE_ENABLE_ASSERTS) 553 return (debugSetting != EGL_FALSE); 554 #else 555 return (debugSetting == EGL_TRUE); 556 #endif // defined(ANGLE_ENABLE_ASSERTS) 557 } 558 559 void CopyImageCHROMIUM(const uint8_t *sourceData, 560 size_t sourceRowPitch, 561 size_t sourcePixelBytes, 562 size_t sourceDepthPitch, 563 PixelReadFunction pixelReadFunction, 564 uint8_t *destData, 565 size_t destRowPitch, 566 size_t destPixelBytes, 567 size_t destDepthPitch, 568 PixelWriteFunction pixelWriteFunction, 569 GLenum destUnsizedFormat, 570 GLenum destComponentType, 571 size_t width, 572 size_t height, 573 size_t depth, 574 bool unpackFlipY, 575 bool unpackPremultiplyAlpha, 576 bool unpackUnmultiplyAlpha) 577 { 578 using ConversionFunction = void (*)(gl::ColorF *); 579 ConversionFunction conversionFunction = CopyColor; 580 if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha) 581 { 582 if (unpackPremultiplyAlpha) 583 { 584 conversionFunction = PremultiplyAlpha; 585 } 586 else 587 { 588 conversionFunction = UnmultiplyAlpha; 589 } 590 } 591 592 auto clipChannelsFunction = ClipChannelsNoOp; 593 switch (destUnsizedFormat) 594 { 595 case GL_RED: 596 clipChannelsFunction = ClipChannelsR; 597 break; 598 case GL_RG: 599 clipChannelsFunction = ClipChannelsRG; 600 break; 601 case GL_RGB: 602 clipChannelsFunction = ClipChannelsRGB; 603 break; 604 case GL_LUMINANCE: 605 clipChannelsFunction = ClipChannelsLuminance; 606 break; 607 case GL_ALPHA: 608 clipChannelsFunction = ClipChannelsAlpha; 609 break; 610 } 611 612 auto writeFunction = (destComponentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor; 613 614 for (size_t z = 0; z < depth; z++) 615 { 616 for (size_t y = 0; y < height; y++) 617 { 618 for (size_t x = 0; x < width; x++) 619 { 620 const uint8_t *sourcePixelData = 621 sourceData + y * sourceRowPitch + x * sourcePixelBytes + z * sourceDepthPitch; 622 623 gl::ColorF sourceColor; 624 pixelReadFunction(sourcePixelData, reinterpret_cast<uint8_t *>(&sourceColor)); 625 626 conversionFunction(&sourceColor); 627 clipChannelsFunction(&sourceColor); 628 629 size_t destY = 0; 630 if (unpackFlipY) 631 { 632 destY += (height - 1); 633 destY -= y; 634 } 635 else 636 { 637 destY += y; 638 } 639 640 uint8_t *destPixelData = 641 destData + destY * destRowPitch + x * destPixelBytes + z * destDepthPitch; 642 writeFunction(sourceColor, pixelWriteFunction, destPixelData); 643 } 644 } 645 } 646 } 647 648 // IncompleteTextureSet implementation. 649 IncompleteTextureSet::IncompleteTextureSet() : mIncompleteTextureBufferAttachment(nullptr) {} 650 651 IncompleteTextureSet::~IncompleteTextureSet() {} 652 653 void IncompleteTextureSet::onDestroy(const gl::Context *context) 654 { 655 // Clear incomplete textures. 656 for (auto &incompleteTextures : mIncompleteTextures) 657 { 658 for (auto &incompleteTexture : incompleteTextures) 659 { 660 if (incompleteTexture.get() != nullptr) 661 { 662 incompleteTexture->onDestroy(context); 663 incompleteTexture.set(context, nullptr); 664 } 665 } 666 } 667 if (mIncompleteTextureBufferAttachment != nullptr) 668 { 669 mIncompleteTextureBufferAttachment->onDestroy(context); 670 mIncompleteTextureBufferAttachment = nullptr; 671 } 672 } 673 674 angle::Result IncompleteTextureSet::getIncompleteTexture( 675 const gl::Context *context, 676 gl::TextureType type, 677 gl::SamplerFormat format, 678 MultisampleTextureInitializer *multisampleInitializer, 679 gl::Texture **textureOut) 680 { 681 *textureOut = mIncompleteTextures[format][type].get(); 682 if (*textureOut != nullptr) 683 { 684 return angle::Result::Continue; 685 } 686 687 ContextImpl *implFactory = context->getImplementation(); 688 689 gl::Extents colorSize(1, 1, 1); 690 gl::PixelUnpackState unpack; 691 unpack.alignment = 1; 692 gl::Box area(0, 0, 0, 1, 1, 1); 693 const IncompleteTextureParameters &incompleteTextureParam = 694 kIncompleteTextureParameters[format]; 695 696 // Cube map arrays are expected to have layer counts that are multiples of 6 697 constexpr int kCubeMapArraySize = 6; 698 if (type == gl::TextureType::CubeMapArray) 699 { 700 // From the GLES 3.2 spec: 701 // 8.18. IMMUTABLE-FORMAT TEXTURE IMAGES 702 // TexStorage3D Errors 703 // An INVALID_OPERATION error is generated if any of the following conditions hold: 704 // * target is TEXTURE_CUBE_MAP_ARRAY and depth is not a multiple of 6 705 // Since ANGLE treats incomplete textures as immutable, respect that here. 706 colorSize.depth = kCubeMapArraySize; 707 area.depth = kCubeMapArraySize; 708 } 709 710 // If a texture is external use a 2D texture for the incomplete texture 711 gl::TextureType createType = (type == gl::TextureType::External) ? gl::TextureType::_2D : type; 712 713 gl::Texture *tex = 714 new gl::Texture(implFactory, {std::numeric_limits<GLuint>::max()}, createType); 715 angle::UniqueObjectPointer<gl::Texture, gl::Context> t(tex, context); 716 717 // This is a bit of a kludge but is necessary to consume the error. 718 gl::Context *mutableContext = const_cast<gl::Context *>(context); 719 720 if (createType == gl::TextureType::Buffer) 721 { 722 constexpr uint32_t kBufferInitData = 0; 723 mIncompleteTextureBufferAttachment = 724 new gl::Buffer(implFactory, {std::numeric_limits<GLuint>::max()}); 725 ANGLE_TRY(mIncompleteTextureBufferAttachment->bufferData( 726 mutableContext, gl::BufferBinding::Texture, &kBufferInitData, sizeof(kBufferInitData), 727 gl::BufferUsage::StaticDraw)); 728 } 729 else if (createType == gl::TextureType::_2DMultisample) 730 { 731 ANGLE_TRY(t->setStorageMultisample(mutableContext, createType, 1, 732 incompleteTextureParam.sizedInternalFormat, colorSize, 733 true)); 734 } 735 else 736 { 737 ANGLE_TRY(t->setStorage(mutableContext, createType, 1, 738 incompleteTextureParam.sizedInternalFormat, colorSize)); 739 } 740 741 if (type == gl::TextureType::CubeMap) 742 { 743 for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets()) 744 { 745 ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr, face, 0, area, 746 incompleteTextureParam.format, incompleteTextureParam.type, 747 incompleteTextureParam.clearColor)); 748 } 749 } 750 else if (type == gl::TextureType::CubeMapArray) 751 { 752 // We need to provide enough pixel data to fill the array of six faces 753 GLubyte incompleteCubeArrayPixels[kCubeMapArraySize][4]; 754 for (int i = 0; i < kCubeMapArraySize; ++i) 755 { 756 incompleteCubeArrayPixels[i][0] = incompleteTextureParam.clearColor[0]; 757 incompleteCubeArrayPixels[i][1] = incompleteTextureParam.clearColor[1]; 758 incompleteCubeArrayPixels[i][2] = incompleteTextureParam.clearColor[2]; 759 incompleteCubeArrayPixels[i][3] = incompleteTextureParam.clearColor[3]; 760 } 761 762 ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr, 763 gl::NonCubeTextureTypeToTarget(createType), 0, area, 764 incompleteTextureParam.format, incompleteTextureParam.type, 765 *incompleteCubeArrayPixels)); 766 } 767 else if (type == gl::TextureType::_2DMultisample) 768 { 769 // Call a specialized clear function to init a multisample texture. 770 ANGLE_TRY(multisampleInitializer->initializeMultisampleTextureToBlack(context, t.get())); 771 } 772 else if (type == gl::TextureType::Buffer) 773 { 774 ANGLE_TRY(t->setBuffer(context, mIncompleteTextureBufferAttachment, 775 incompleteTextureParam.sizedInternalFormat)); 776 } 777 else 778 { 779 ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr, 780 gl::NonCubeTextureTypeToTarget(createType), 0, area, 781 incompleteTextureParam.format, incompleteTextureParam.type, 782 incompleteTextureParam.clearColor)); 783 } 784 785 if (format == gl::SamplerFormat::Shadow) 786 { 787 // To avoid the undefined spec behavior for shadow samplers with a depth texture, we set the 788 // compare mode to GL_COMPARE_REF_TO_TEXTURE 789 ASSERT(!t->hasObservers()); 790 t->setCompareMode(context, GL_COMPARE_REF_TO_TEXTURE); 791 } 792 793 ANGLE_TRY(t->syncState(context, gl::Command::Other)); 794 795 mIncompleteTextures[format][type].set(context, t.release()); 796 *textureOut = mIncompleteTextures[format][type].get(); 797 return angle::Result::Continue; 798 } 799 800 #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \ 801 template void SetFloatUniformMatrix##api<cols, rows>::Run( \ 802 unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *) 803 804 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 2); 805 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 3); 806 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 3); 807 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 2); 808 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 2); 809 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 3); 810 811 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 2); 812 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 3); 813 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 3); 814 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 2); 815 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 2, 4); 816 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(HLSL, 3, 4); 817 818 #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC 819 820 #define ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \ 821 template void SetFloatUniformMatrix##api<cols, 4>::Run(unsigned int, unsigned int, GLsizei, \ 822 GLboolean, const GLfloat *, uint8_t *) 823 824 template <int cols> 825 struct SetFloatUniformMatrixGLSL<cols, 4> 826 { 827 static void Run(unsigned int arrayElementOffset, 828 unsigned int elementCount, 829 GLsizei countIn, 830 GLboolean transpose, 831 const GLfloat *value, 832 uint8_t *targetData); 833 }; 834 835 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 2, 4); 836 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 3, 4); 837 ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC(GLSL, 4, 4); 838 839 #undef ANGLE_SPECIALIZATION_ROWS_SET_UNIFORM_MATRIX_FUNC 840 841 #define ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \ 842 template void SetFloatUniformMatrix##api<4, rows>::Run(unsigned int, unsigned int, GLsizei, \ 843 GLboolean, const GLfloat *, uint8_t *) 844 845 template <int rows> 846 struct SetFloatUniformMatrixHLSL<4, rows> 847 { 848 static void Run(unsigned int arrayElementOffset, 849 unsigned int elementCount, 850 GLsizei countIn, 851 GLboolean transpose, 852 const GLfloat *value, 853 uint8_t *targetData); 854 }; 855 856 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 2); 857 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 3); 858 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(HLSL, 4, 4); 859 860 #undef ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC 861 862 template <int cols> 863 void SetFloatUniformMatrixGLSL<cols, 4>::Run(unsigned int arrayElementOffset, 864 unsigned int elementCount, 865 GLsizei countIn, 866 GLboolean transpose, 867 const GLfloat *value, 868 uint8_t *targetData) 869 { 870 const bool isSrcColumnMajor = !transpose; 871 if (isSrcColumnMajor) 872 { 873 // Both src and dst matrixs are has same layout, 874 // a single memcpy updates all the matrices 875 constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 4; 876 SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value, 877 targetData); 878 } 879 else 880 { 881 // fallback to general cases 882 SetFloatUniformMatrix<false, cols, 4, true, cols, 4>(arrayElementOffset, elementCount, 883 countIn, value, targetData); 884 } 885 } 886 887 template <int cols, int rows> 888 void SetFloatUniformMatrixGLSL<cols, rows>::Run(unsigned int arrayElementOffset, 889 unsigned int elementCount, 890 GLsizei countIn, 891 GLboolean transpose, 892 const GLfloat *value, 893 uint8_t *targetData) 894 { 895 const bool isSrcColumnMajor = !transpose; 896 // GLSL expects matrix uniforms to be column-major, and each column is padded to 4 rows. 897 if (isSrcColumnMajor) 898 { 899 SetFloatUniformMatrix<true, cols, rows, true, cols, 4>(arrayElementOffset, elementCount, 900 countIn, value, targetData); 901 } 902 else 903 { 904 SetFloatUniformMatrix<false, cols, rows, true, cols, 4>(arrayElementOffset, elementCount, 905 countIn, value, targetData); 906 } 907 } 908 909 template <int rows> 910 void SetFloatUniformMatrixHLSL<4, rows>::Run(unsigned int arrayElementOffset, 911 unsigned int elementCount, 912 GLsizei countIn, 913 GLboolean transpose, 914 const GLfloat *value, 915 uint8_t *targetData) 916 { 917 const bool isSrcColumnMajor = !transpose; 918 if (!isSrcColumnMajor) 919 { 920 // Both src and dst matrixs are has same layout, 921 // a single memcpy updates all the matrices 922 constexpr size_t srcMatrixSize = sizeof(GLfloat) * 4 * rows; 923 SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value, 924 targetData); 925 } 926 else 927 { 928 // fallback to general cases 929 SetFloatUniformMatrix<true, 4, rows, false, 4, rows>(arrayElementOffset, elementCount, 930 countIn, value, targetData); 931 } 932 } 933 934 template <int cols, int rows> 935 void SetFloatUniformMatrixHLSL<cols, rows>::Run(unsigned int arrayElementOffset, 936 unsigned int elementCount, 937 GLsizei countIn, 938 GLboolean transpose, 939 const GLfloat *value, 940 uint8_t *targetData) 941 { 942 const bool isSrcColumnMajor = !transpose; 943 // Internally store matrices as row-major to accomodate HLSL matrix indexing. Each row is 944 // padded to 4 columns. 945 if (!isSrcColumnMajor) 946 { 947 SetFloatUniformMatrix<false, cols, rows, false, 4, rows>(arrayElementOffset, elementCount, 948 countIn, value, targetData); 949 } 950 else 951 { 952 SetFloatUniformMatrix<true, cols, rows, false, 4, rows>(arrayElementOffset, elementCount, 953 countIn, value, targetData); 954 } 955 } 956 957 template void GetMatrixUniform<GLint>(GLenum, GLint *, const GLint *, bool); 958 template void GetMatrixUniform<GLuint>(GLenum, GLuint *, const GLuint *, bool); 959 960 void GetMatrixUniform(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose) 961 { 962 int columns = gl::VariableColumnCount(type); 963 int rows = gl::VariableRowCount(type); 964 for (GLint col = 0; col < columns; ++col) 965 { 966 for (GLint row = 0; row < rows; ++row) 967 { 968 GLfloat *outptr = dataOut + ((col * rows) + row); 969 const GLfloat *inptr = 970 transpose ? source + ((row * 4) + col) : source + ((col * 4) + row); 971 *outptr = *inptr; 972 } 973 } 974 } 975 976 template <typename NonFloatT> 977 void GetMatrixUniform(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose) 978 { 979 UNREACHABLE(); 980 } 981 982 const angle::Format &GetFormatFromFormatType(GLenum format, GLenum type) 983 { 984 GLenum sizedInternalFormat = gl::GetInternalFormatInfo(format, type).sizedInternalFormat; 985 angle::FormatID angleFormatID = angle::Format::InternalFormatToID(sizedInternalFormat); 986 return angle::Format::Get(angleFormatID); 987 } 988 989 angle::Result ComputeStartVertex(ContextImpl *contextImpl, 990 const gl::IndexRange &indexRange, 991 GLint baseVertex, 992 GLint *firstVertexOut) 993 { 994 // The entire index range should be within the limits of a 32-bit uint because the largest 995 // GL index type is GL_UNSIGNED_INT. 996 ASSERT(indexRange.start <= std::numeric_limits<uint32_t>::max() && 997 indexRange.end <= std::numeric_limits<uint32_t>::max()); 998 999 // The base vertex is only used in DrawElementsIndirect. Given the assertion above and the 1000 // type of mBaseVertex (GLint), adding them both as 64-bit ints is safe. 1001 int64_t startVertexInt64 = 1002 static_cast<int64_t>(baseVertex) + static_cast<int64_t>(indexRange.start); 1003 1004 // OpenGL ES 3.2 spec section 10.5: "Behavior of DrawElementsOneInstance is undefined if the 1005 // vertex ID is negative for any element" 1006 ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 >= 0); 1007 1008 // OpenGL ES 3.2 spec section 10.5: "If the vertex ID is larger than the maximum value 1009 // representable by type, it should behave as if the calculation were upconverted to 32-bit 1010 // unsigned integers(with wrapping on overflow conditions)." ANGLE does not fully handle 1011 // these rules, an overflow error is returned if the start vertex cannot be stored in a 1012 // 32-bit signed integer. 1013 ANGLE_CHECK_GL_MATH(contextImpl, startVertexInt64 <= std::numeric_limits<GLint>::max()); 1014 1015 *firstVertexOut = static_cast<GLint>(startVertexInt64); 1016 return angle::Result::Continue; 1017 } 1018 1019 angle::Result GetVertexRangeInfo(const gl::Context *context, 1020 GLint firstVertex, 1021 GLsizei vertexOrIndexCount, 1022 gl::DrawElementsType indexTypeOrInvalid, 1023 const void *indices, 1024 GLint baseVertex, 1025 GLint *startVertexOut, 1026 size_t *vertexCountOut) 1027 { 1028 if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum) 1029 { 1030 gl::IndexRange indexRange; 1031 ANGLE_TRY(context->getState().getVertexArray()->getIndexRange( 1032 context, indexTypeOrInvalid, vertexOrIndexCount, indices, &indexRange)); 1033 ANGLE_TRY(ComputeStartVertex(context->getImplementation(), indexRange, baseVertex, 1034 startVertexOut)); 1035 *vertexCountOut = indexRange.vertexCount(); 1036 } 1037 else 1038 { 1039 *startVertexOut = firstVertex; 1040 *vertexCountOut = vertexOrIndexCount; 1041 } 1042 return angle::Result::Continue; 1043 } 1044 1045 gl::Rectangle ClipRectToScissor(const gl::State &glState, const gl::Rectangle &rect, bool invertY) 1046 { 1047 // If the scissor test isn't enabled, assume it has infinite size. Its intersection with the 1048 // rect would be the rect itself. 1049 // 1050 // Note that on Vulkan, returning this (as opposed to a fixed max-int-sized rect) could lead to 1051 // unnecessary pipeline creations if two otherwise identical pipelines are used on framebuffers 1052 // with different sizes. If such usage is observed in an application, we should investigate 1053 // possible optimizations. 1054 if (!glState.isScissorTestEnabled()) 1055 { 1056 return rect; 1057 } 1058 1059 gl::Rectangle clippedRect; 1060 if (!gl::ClipRectangle(glState.getScissor(), rect, &clippedRect)) 1061 { 1062 return gl::Rectangle(); 1063 } 1064 1065 if (invertY) 1066 { 1067 clippedRect.y = rect.height - clippedRect.y - clippedRect.height; 1068 } 1069 1070 return clippedRect; 1071 } 1072 1073 void LogFeatureStatus(const angle::FeatureSetBase &features, 1074 const std::vector<std::string> &featureNames, 1075 bool enabled) 1076 { 1077 for (const std::string &name : featureNames) 1078 { 1079 const bool hasWildcard = name.back() == '*'; 1080 for (auto iter : features.getFeatures()) 1081 { 1082 const std::string &featureName = iter.first; 1083 1084 if (!angle::FeatureNameMatch(featureName, name)) 1085 { 1086 continue; 1087 } 1088 1089 INFO() << "Feature: " << featureName << (enabled ? " enabled" : " disabled"); 1090 1091 if (!hasWildcard) 1092 { 1093 break; 1094 } 1095 } 1096 } 1097 } 1098 1099 void ApplyFeatureOverrides(angle::FeatureSetBase *features, const egl::DisplayState &state) 1100 { 1101 features->overrideFeatures(state.featureOverridesEnabled, true); 1102 features->overrideFeatures(state.featureOverridesDisabled, false); 1103 1104 // Override with environment as well. 1105 constexpr char kAngleFeatureOverridesEnabledEnvName[] = "ANGLE_FEATURE_OVERRIDES_ENABLED"; 1106 constexpr char kAngleFeatureOverridesDisabledEnvName[] = "ANGLE_FEATURE_OVERRIDES_DISABLED"; 1107 constexpr char kAngleFeatureOverridesEnabledPropertyName[] = 1108 "debug.angle.feature_overrides_enabled"; 1109 constexpr char kAngleFeatureOverridesDisabledPropertyName[] = 1110 "debug.angle.feature_overrides_disabled"; 1111 std::vector<std::string> overridesEnabled = 1112 angle::GetCachedStringsFromEnvironmentVarOrAndroidProperty( 1113 kAngleFeatureOverridesEnabledEnvName, kAngleFeatureOverridesEnabledPropertyName, ":"); 1114 std::vector<std::string> overridesDisabled = 1115 angle::GetCachedStringsFromEnvironmentVarOrAndroidProperty( 1116 kAngleFeatureOverridesDisabledEnvName, kAngleFeatureOverridesDisabledPropertyName, ":"); 1117 1118 features->overrideFeatures(overridesEnabled, true); 1119 LogFeatureStatus(*features, overridesEnabled, true); 1120 1121 features->overrideFeatures(overridesDisabled, false); 1122 LogFeatureStatus(*features, overridesDisabled, false); 1123 } 1124 1125 void GetSamplePosition(GLsizei sampleCount, size_t index, GLfloat *xy) 1126 { 1127 ASSERT(gl::isPow2(sampleCount)); 1128 if (sampleCount > 16) 1129 { 1130 // Vulkan (and D3D11) doesn't have standard sample positions for 32 and 64 samples (and no 1131 // drivers are known to support that many samples) 1132 xy[0] = 0.5f; 1133 xy[1] = 0.5f; 1134 } 1135 else 1136 { 1137 size_t indexKey = static_cast<size_t>(gl::log2(sampleCount)); 1138 ASSERT(indexKey < kSamplePositions.size() && 1139 (2 * index + 1) < kSamplePositions[indexKey].size()); 1140 1141 xy[0] = kSamplePositions[indexKey][2 * index]; 1142 xy[1] = kSamplePositions[indexKey][2 * index + 1]; 1143 } 1144 } 1145 1146 // These macros are to avoid code too much duplication for variations of multi draw types 1147 #define DRAW_ARRAYS__ contextImpl->drawArrays(context, mode, firsts[drawID], counts[drawID]) 1148 #define DRAW_ARRAYS_INSTANCED_ \ 1149 contextImpl->drawArraysInstanced(context, mode, firsts[drawID], counts[drawID], \ 1150 instanceCounts[drawID]) 1151 #define DRAW_ELEMENTS__ \ 1152 contextImpl->drawElements(context, mode, counts[drawID], type, indices[drawID]) 1153 #define DRAW_ELEMENTS_INSTANCED_ \ 1154 contextImpl->drawElementsInstanced(context, mode, counts[drawID], type, indices[drawID], \ 1155 instanceCounts[drawID]) 1156 #define DRAW_ARRAYS_INSTANCED_BASE_INSTANCE \ 1157 contextImpl->drawArraysInstancedBaseInstance(context, mode, firsts[drawID], counts[drawID], \ 1158 instanceCounts[drawID], baseInstances[drawID]) 1159 #define DRAW_ELEMENTS_INSTANCED_BASE_VERTEX_BASE_INSTANCE \ 1160 contextImpl->drawElementsInstancedBaseVertexBaseInstance( \ 1161 context, mode, counts[drawID], type, indices[drawID], instanceCounts[drawID], \ 1162 baseVertices[drawID], baseInstances[drawID]) 1163 #define DRAW_CALL(drawType, instanced, bvbi) DRAW_##drawType##instanced##bvbi 1164 1165 #define MULTI_DRAW_BLOCK(drawType, instanced, bvbi, hasDrawID, hasBaseVertex, hasBaseInstance) \ 1166 for (GLsizei drawID = 0; drawID < drawcount; ++drawID) \ 1167 { \ 1168 if (ANGLE_NOOP_DRAW(instanced)) \ 1169 { \ 1170 ANGLE_TRY(contextImpl->handleNoopDrawEvent()); \ 1171 continue; \ 1172 } \ 1173 ANGLE_SET_DRAW_ID_UNIFORM(hasDrawID)(drawID); \ 1174 ANGLE_SET_BASE_VERTEX_UNIFORM(hasBaseVertex)(baseVertices[drawID]); \ 1175 ANGLE_SET_BASE_INSTANCE_UNIFORM(hasBaseInstance)(baseInstances[drawID]); \ 1176 ANGLE_TRY(DRAW_CALL(drawType, instanced, bvbi)); \ 1177 ANGLE_MARK_TRANSFORM_FEEDBACK_USAGE(instanced); \ 1178 gl::MarkShaderStorageUsage(context); \ 1179 } 1180 1181 angle::Result MultiDrawArraysGeneral(ContextImpl *contextImpl, 1182 const gl::Context *context, 1183 gl::PrimitiveMode mode, 1184 const GLint *firsts, 1185 const GLsizei *counts, 1186 GLsizei drawcount) 1187 { 1188 gl::Program *programObject = context->getState().getLinkedProgram(context); 1189 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1190 if (hasDrawID) 1191 { 1192 MULTI_DRAW_BLOCK(ARRAYS, _, _, 1, 0, 0) 1193 } 1194 else 1195 { 1196 MULTI_DRAW_BLOCK(ARRAYS, _, _, 0, 0, 0) 1197 } 1198 1199 return angle::Result::Continue; 1200 } 1201 1202 angle::Result MultiDrawArraysIndirectGeneral(ContextImpl *contextImpl, 1203 const gl::Context *context, 1204 gl::PrimitiveMode mode, 1205 const void *indirect, 1206 GLsizei drawcount, 1207 GLsizei stride) 1208 { 1209 const GLubyte *indirectPtr = static_cast<const GLubyte *>(indirect); 1210 1211 for (auto count = 0; count < drawcount; count++) 1212 { 1213 ANGLE_TRY(contextImpl->drawArraysIndirect( 1214 context, mode, reinterpret_cast<const gl::DrawArraysIndirectCommand *>(indirectPtr))); 1215 if (stride == 0) 1216 { 1217 indirectPtr += sizeof(gl::DrawArraysIndirectCommand); 1218 } 1219 else 1220 { 1221 indirectPtr += stride; 1222 } 1223 } 1224 1225 return angle::Result::Continue; 1226 } 1227 1228 angle::Result MultiDrawArraysInstancedGeneral(ContextImpl *contextImpl, 1229 const gl::Context *context, 1230 gl::PrimitiveMode mode, 1231 const GLint *firsts, 1232 const GLsizei *counts, 1233 const GLsizei *instanceCounts, 1234 GLsizei drawcount) 1235 { 1236 gl::Program *programObject = context->getState().getLinkedProgram(context); 1237 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1238 if (hasDrawID) 1239 { 1240 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 1, 0, 0) 1241 } 1242 else 1243 { 1244 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _, 0, 0, 0) 1245 } 1246 1247 return angle::Result::Continue; 1248 } 1249 1250 angle::Result MultiDrawElementsGeneral(ContextImpl *contextImpl, 1251 const gl::Context *context, 1252 gl::PrimitiveMode mode, 1253 const GLsizei *counts, 1254 gl::DrawElementsType type, 1255 const GLvoid *const *indices, 1256 GLsizei drawcount) 1257 { 1258 gl::Program *programObject = context->getState().getLinkedProgram(context); 1259 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1260 if (hasDrawID) 1261 { 1262 MULTI_DRAW_BLOCK(ELEMENTS, _, _, 1, 0, 0) 1263 } 1264 else 1265 { 1266 MULTI_DRAW_BLOCK(ELEMENTS, _, _, 0, 0, 0) 1267 } 1268 1269 return angle::Result::Continue; 1270 } 1271 1272 angle::Result MultiDrawElementsIndirectGeneral(ContextImpl *contextImpl, 1273 const gl::Context *context, 1274 gl::PrimitiveMode mode, 1275 gl::DrawElementsType type, 1276 const void *indirect, 1277 GLsizei drawcount, 1278 GLsizei stride) 1279 { 1280 const GLubyte *indirectPtr = static_cast<const GLubyte *>(indirect); 1281 1282 for (auto count = 0; count < drawcount; count++) 1283 { 1284 ANGLE_TRY(contextImpl->drawElementsIndirect( 1285 context, mode, type, 1286 reinterpret_cast<const gl::DrawElementsIndirectCommand *>(indirectPtr))); 1287 if (stride == 0) 1288 { 1289 indirectPtr += sizeof(gl::DrawElementsIndirectCommand); 1290 } 1291 else 1292 { 1293 indirectPtr += stride; 1294 } 1295 } 1296 1297 return angle::Result::Continue; 1298 } 1299 1300 angle::Result MultiDrawElementsInstancedGeneral(ContextImpl *contextImpl, 1301 const gl::Context *context, 1302 gl::PrimitiveMode mode, 1303 const GLsizei *counts, 1304 gl::DrawElementsType type, 1305 const GLvoid *const *indices, 1306 const GLsizei *instanceCounts, 1307 GLsizei drawcount) 1308 { 1309 gl::Program *programObject = context->getState().getLinkedProgram(context); 1310 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1311 if (hasDrawID) 1312 { 1313 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 1, 0, 0) 1314 } 1315 else 1316 { 1317 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _, 0, 0, 0) 1318 } 1319 1320 return angle::Result::Continue; 1321 } 1322 1323 angle::Result MultiDrawArraysInstancedBaseInstanceGeneral(ContextImpl *contextImpl, 1324 const gl::Context *context, 1325 gl::PrimitiveMode mode, 1326 const GLint *firsts, 1327 const GLsizei *counts, 1328 const GLsizei *instanceCounts, 1329 const GLuint *baseInstances, 1330 GLsizei drawcount) 1331 { 1332 gl::Program *programObject = context->getState().getLinkedProgram(context); 1333 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1334 const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform(); 1335 ResetBaseVertexBaseInstance resetUniforms(programObject, false, hasBaseInstance); 1336 1337 if (hasDrawID && hasBaseInstance) 1338 { 1339 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 1) 1340 } 1341 else if (hasDrawID) 1342 { 1343 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 1, 0, 0) 1344 } 1345 else if (hasBaseInstance) 1346 { 1347 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 1) 1348 } 1349 else 1350 { 1351 MULTI_DRAW_BLOCK(ARRAYS, _INSTANCED, _BASE_INSTANCE, 0, 0, 0) 1352 } 1353 1354 return angle::Result::Continue; 1355 } 1356 1357 angle::Result MultiDrawElementsInstancedBaseVertexBaseInstanceGeneral(ContextImpl *contextImpl, 1358 const gl::Context *context, 1359 gl::PrimitiveMode mode, 1360 const GLsizei *counts, 1361 gl::DrawElementsType type, 1362 const GLvoid *const *indices, 1363 const GLsizei *instanceCounts, 1364 const GLint *baseVertices, 1365 const GLuint *baseInstances, 1366 GLsizei drawcount) 1367 { 1368 gl::Program *programObject = context->getState().getLinkedProgram(context); 1369 const bool hasDrawID = programObject && programObject->hasDrawIDUniform(); 1370 const bool hasBaseVertex = programObject && programObject->hasBaseVertexUniform(); 1371 const bool hasBaseInstance = programObject && programObject->hasBaseInstanceUniform(); 1372 ResetBaseVertexBaseInstance resetUniforms(programObject, hasBaseVertex, hasBaseInstance); 1373 1374 if (hasDrawID) 1375 { 1376 if (hasBaseVertex) 1377 { 1378 if (hasBaseInstance) 1379 { 1380 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 1) 1381 } 1382 else 1383 { 1384 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 1, 0) 1385 } 1386 } 1387 else 1388 { 1389 if (hasBaseInstance) 1390 { 1391 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 1) 1392 } 1393 else 1394 { 1395 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 1, 0, 0) 1396 } 1397 } 1398 } 1399 else 1400 { 1401 if (hasBaseVertex) 1402 { 1403 if (hasBaseInstance) 1404 { 1405 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 1) 1406 } 1407 else 1408 { 1409 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 1, 0) 1410 } 1411 } 1412 else 1413 { 1414 if (hasBaseInstance) 1415 { 1416 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 1) 1417 } 1418 else 1419 { 1420 MULTI_DRAW_BLOCK(ELEMENTS, _INSTANCED, _BASE_VERTEX_BASE_INSTANCE, 0, 0, 0) 1421 } 1422 } 1423 } 1424 1425 return angle::Result::Continue; 1426 } 1427 1428 ResetBaseVertexBaseInstance::ResetBaseVertexBaseInstance(gl::Program *programObject, 1429 bool resetBaseVertex, 1430 bool resetBaseInstance) 1431 : mProgramObject(programObject), 1432 mResetBaseVertex(resetBaseVertex), 1433 mResetBaseInstance(resetBaseInstance) 1434 {} 1435 1436 ResetBaseVertexBaseInstance::~ResetBaseVertexBaseInstance() 1437 { 1438 if (mProgramObject) 1439 { 1440 // Reset emulated uniforms to zero to avoid affecting other draw calls 1441 if (mResetBaseVertex) 1442 { 1443 mProgramObject->setBaseVertexUniform(0); 1444 } 1445 1446 if (mResetBaseInstance) 1447 { 1448 mProgramObject->setBaseInstanceUniform(0); 1449 } 1450 } 1451 } 1452 1453 angle::FormatID ConvertToSRGB(angle::FormatID formatID) 1454 { 1455 switch (formatID) 1456 { 1457 case angle::FormatID::R8_UNORM: 1458 return angle::FormatID::R8_UNORM_SRGB; 1459 case angle::FormatID::R8G8_UNORM: 1460 return angle::FormatID::R8G8_UNORM_SRGB; 1461 case angle::FormatID::R8G8B8_UNORM: 1462 return angle::FormatID::R8G8B8_UNORM_SRGB; 1463 case angle::FormatID::R8G8B8A8_UNORM: 1464 return angle::FormatID::R8G8B8A8_UNORM_SRGB; 1465 case angle::FormatID::B8G8R8A8_UNORM: 1466 return angle::FormatID::B8G8R8A8_UNORM_SRGB; 1467 case angle::FormatID::BC1_RGB_UNORM_BLOCK: 1468 return angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK; 1469 case angle::FormatID::BC1_RGBA_UNORM_BLOCK: 1470 return angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK; 1471 case angle::FormatID::BC2_RGBA_UNORM_BLOCK: 1472 return angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK; 1473 case angle::FormatID::BC3_RGBA_UNORM_BLOCK: 1474 return angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK; 1475 case angle::FormatID::BC7_RGBA_UNORM_BLOCK: 1476 return angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK; 1477 case angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK: 1478 return angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK; 1479 case angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK: 1480 return angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK; 1481 case angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK: 1482 return angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK; 1483 case angle::FormatID::ASTC_4x4_UNORM_BLOCK: 1484 return angle::FormatID::ASTC_4x4_SRGB_BLOCK; 1485 case angle::FormatID::ASTC_5x4_UNORM_BLOCK: 1486 return angle::FormatID::ASTC_5x4_SRGB_BLOCK; 1487 case angle::FormatID::ASTC_5x5_UNORM_BLOCK: 1488 return angle::FormatID::ASTC_5x5_SRGB_BLOCK; 1489 case angle::FormatID::ASTC_6x5_UNORM_BLOCK: 1490 return angle::FormatID::ASTC_6x5_SRGB_BLOCK; 1491 case angle::FormatID::ASTC_6x6_UNORM_BLOCK: 1492 return angle::FormatID::ASTC_6x6_SRGB_BLOCK; 1493 case angle::FormatID::ASTC_8x5_UNORM_BLOCK: 1494 return angle::FormatID::ASTC_8x5_SRGB_BLOCK; 1495 case angle::FormatID::ASTC_8x6_UNORM_BLOCK: 1496 return angle::FormatID::ASTC_8x6_SRGB_BLOCK; 1497 case angle::FormatID::ASTC_8x8_UNORM_BLOCK: 1498 return angle::FormatID::ASTC_8x8_SRGB_BLOCK; 1499 case angle::FormatID::ASTC_10x5_UNORM_BLOCK: 1500 return angle::FormatID::ASTC_10x5_SRGB_BLOCK; 1501 case angle::FormatID::ASTC_10x6_UNORM_BLOCK: 1502 return angle::FormatID::ASTC_10x6_SRGB_BLOCK; 1503 case angle::FormatID::ASTC_10x8_UNORM_BLOCK: 1504 return angle::FormatID::ASTC_10x8_SRGB_BLOCK; 1505 case angle::FormatID::ASTC_10x10_UNORM_BLOCK: 1506 return angle::FormatID::ASTC_10x10_SRGB_BLOCK; 1507 case angle::FormatID::ASTC_12x10_UNORM_BLOCK: 1508 return angle::FormatID::ASTC_12x10_SRGB_BLOCK; 1509 case angle::FormatID::ASTC_12x12_UNORM_BLOCK: 1510 return angle::FormatID::ASTC_12x12_SRGB_BLOCK; 1511 default: 1512 return angle::FormatID::NONE; 1513 } 1514 } 1515 1516 angle::FormatID ConvertToLinear(angle::FormatID formatID) 1517 { 1518 switch (formatID) 1519 { 1520 case angle::FormatID::R8_UNORM_SRGB: 1521 return angle::FormatID::R8_UNORM; 1522 case angle::FormatID::R8G8_UNORM_SRGB: 1523 return angle::FormatID::R8G8_UNORM; 1524 case angle::FormatID::R8G8B8_UNORM_SRGB: 1525 return angle::FormatID::R8G8B8_UNORM; 1526 case angle::FormatID::R8G8B8A8_UNORM_SRGB: 1527 return angle::FormatID::R8G8B8A8_UNORM; 1528 case angle::FormatID::B8G8R8A8_UNORM_SRGB: 1529 return angle::FormatID::B8G8R8A8_UNORM; 1530 case angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK: 1531 return angle::FormatID::BC1_RGB_UNORM_BLOCK; 1532 case angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK: 1533 return angle::FormatID::BC1_RGBA_UNORM_BLOCK; 1534 case angle::FormatID::BC2_RGBA_UNORM_SRGB_BLOCK: 1535 return angle::FormatID::BC2_RGBA_UNORM_BLOCK; 1536 case angle::FormatID::BC3_RGBA_UNORM_SRGB_BLOCK: 1537 return angle::FormatID::BC3_RGBA_UNORM_BLOCK; 1538 case angle::FormatID::BC7_RGBA_UNORM_SRGB_BLOCK: 1539 return angle::FormatID::BC7_RGBA_UNORM_BLOCK; 1540 case angle::FormatID::ETC2_R8G8B8_SRGB_BLOCK: 1541 return angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK; 1542 case angle::FormatID::ETC2_R8G8B8A1_SRGB_BLOCK: 1543 return angle::FormatID::ETC2_R8G8B8A1_UNORM_BLOCK; 1544 case angle::FormatID::ETC2_R8G8B8A8_SRGB_BLOCK: 1545 return angle::FormatID::ETC2_R8G8B8A8_UNORM_BLOCK; 1546 case angle::FormatID::ASTC_4x4_SRGB_BLOCK: 1547 return angle::FormatID::ASTC_4x4_UNORM_BLOCK; 1548 case angle::FormatID::ASTC_5x4_SRGB_BLOCK: 1549 return angle::FormatID::ASTC_5x4_UNORM_BLOCK; 1550 case angle::FormatID::ASTC_5x5_SRGB_BLOCK: 1551 return angle::FormatID::ASTC_5x5_UNORM_BLOCK; 1552 case angle::FormatID::ASTC_6x5_SRGB_BLOCK: 1553 return angle::FormatID::ASTC_6x5_UNORM_BLOCK; 1554 case angle::FormatID::ASTC_6x6_SRGB_BLOCK: 1555 return angle::FormatID::ASTC_6x6_UNORM_BLOCK; 1556 case angle::FormatID::ASTC_8x5_SRGB_BLOCK: 1557 return angle::FormatID::ASTC_8x5_UNORM_BLOCK; 1558 case angle::FormatID::ASTC_8x6_SRGB_BLOCK: 1559 return angle::FormatID::ASTC_8x6_UNORM_BLOCK; 1560 case angle::FormatID::ASTC_8x8_SRGB_BLOCK: 1561 return angle::FormatID::ASTC_8x8_UNORM_BLOCK; 1562 case angle::FormatID::ASTC_10x5_SRGB_BLOCK: 1563 return angle::FormatID::ASTC_10x5_UNORM_BLOCK; 1564 case angle::FormatID::ASTC_10x6_SRGB_BLOCK: 1565 return angle::FormatID::ASTC_10x6_UNORM_BLOCK; 1566 case angle::FormatID::ASTC_10x8_SRGB_BLOCK: 1567 return angle::FormatID::ASTC_10x8_UNORM_BLOCK; 1568 case angle::FormatID::ASTC_10x10_SRGB_BLOCK: 1569 return angle::FormatID::ASTC_10x10_UNORM_BLOCK; 1570 case angle::FormatID::ASTC_12x10_SRGB_BLOCK: 1571 return angle::FormatID::ASTC_12x10_UNORM_BLOCK; 1572 case angle::FormatID::ASTC_12x12_SRGB_BLOCK: 1573 return angle::FormatID::ASTC_12x12_UNORM_BLOCK; 1574 default: 1575 return angle::FormatID::NONE; 1576 } 1577 } 1578 1579 bool IsOverridableLinearFormat(angle::FormatID formatID) 1580 { 1581 return ConvertToSRGB(formatID) != angle::FormatID::NONE; 1582 } 1583 } // namespace rx