renderer9_utils.cpp (30800B)
1 // 2 // Copyright 2002 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 7 // renderer9_utils.cpp: Conversion functions and other utility routines 8 // specific to the D3D9 renderer. 9 10 #include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" 11 12 #include "common/debug.h" 13 #include "common/mathutil.h" 14 15 #include "libANGLE/formatutils.h" 16 #include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" 17 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h" 18 #include "libANGLE/renderer/driver_utils.h" 19 #include "platform/FeaturesD3D_autogen.h" 20 #include "platform/PlatformMethods.h" 21 22 #include "third_party/systeminfo/SystemInfo.h" 23 24 namespace rx 25 { 26 27 namespace gl_d3d9 28 { 29 30 D3DCMPFUNC ConvertComparison(GLenum comparison) 31 { 32 D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; 33 switch (comparison) 34 { 35 case GL_NEVER: 36 d3dComp = D3DCMP_NEVER; 37 break; 38 case GL_ALWAYS: 39 d3dComp = D3DCMP_ALWAYS; 40 break; 41 case GL_LESS: 42 d3dComp = D3DCMP_LESS; 43 break; 44 case GL_LEQUAL: 45 d3dComp = D3DCMP_LESSEQUAL; 46 break; 47 case GL_EQUAL: 48 d3dComp = D3DCMP_EQUAL; 49 break; 50 case GL_GREATER: 51 d3dComp = D3DCMP_GREATER; 52 break; 53 case GL_GEQUAL: 54 d3dComp = D3DCMP_GREATEREQUAL; 55 break; 56 case GL_NOTEQUAL: 57 d3dComp = D3DCMP_NOTEQUAL; 58 break; 59 default: 60 UNREACHABLE(); 61 } 62 63 return d3dComp; 64 } 65 66 D3DCOLOR ConvertColor(gl::ColorF color) 67 { 68 return D3DCOLOR_RGBA(gl::unorm<8>(color.red), gl::unorm<8>(color.green), 69 gl::unorm<8>(color.blue), gl::unorm<8>(color.alpha)); 70 } 71 72 D3DBLEND ConvertBlendFunc(GLenum blend) 73 { 74 D3DBLEND d3dBlend = D3DBLEND_ZERO; 75 76 switch (blend) 77 { 78 case GL_ZERO: 79 d3dBlend = D3DBLEND_ZERO; 80 break; 81 case GL_ONE: 82 d3dBlend = D3DBLEND_ONE; 83 break; 84 case GL_SRC_COLOR: 85 d3dBlend = D3DBLEND_SRCCOLOR; 86 break; 87 case GL_ONE_MINUS_SRC_COLOR: 88 d3dBlend = D3DBLEND_INVSRCCOLOR; 89 break; 90 case GL_DST_COLOR: 91 d3dBlend = D3DBLEND_DESTCOLOR; 92 break; 93 case GL_ONE_MINUS_DST_COLOR: 94 d3dBlend = D3DBLEND_INVDESTCOLOR; 95 break; 96 case GL_SRC_ALPHA: 97 d3dBlend = D3DBLEND_SRCALPHA; 98 break; 99 case GL_ONE_MINUS_SRC_ALPHA: 100 d3dBlend = D3DBLEND_INVSRCALPHA; 101 break; 102 case GL_DST_ALPHA: 103 d3dBlend = D3DBLEND_DESTALPHA; 104 break; 105 case GL_ONE_MINUS_DST_ALPHA: 106 d3dBlend = D3DBLEND_INVDESTALPHA; 107 break; 108 case GL_CONSTANT_COLOR: 109 d3dBlend = D3DBLEND_BLENDFACTOR; 110 break; 111 case GL_ONE_MINUS_CONSTANT_COLOR: 112 d3dBlend = D3DBLEND_INVBLENDFACTOR; 113 break; 114 case GL_CONSTANT_ALPHA: 115 d3dBlend = D3DBLEND_BLENDFACTOR; 116 break; 117 case GL_ONE_MINUS_CONSTANT_ALPHA: 118 d3dBlend = D3DBLEND_INVBLENDFACTOR; 119 break; 120 case GL_SRC_ALPHA_SATURATE: 121 d3dBlend = D3DBLEND_SRCALPHASAT; 122 break; 123 default: 124 UNREACHABLE(); 125 } 126 127 return d3dBlend; 128 } 129 130 D3DBLENDOP ConvertBlendOp(GLenum blendOp) 131 { 132 D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; 133 134 switch (blendOp) 135 { 136 case GL_FUNC_ADD: 137 d3dBlendOp = D3DBLENDOP_ADD; 138 break; 139 case GL_FUNC_SUBTRACT: 140 d3dBlendOp = D3DBLENDOP_SUBTRACT; 141 break; 142 case GL_FUNC_REVERSE_SUBTRACT: 143 d3dBlendOp = D3DBLENDOP_REVSUBTRACT; 144 break; 145 case GL_MIN_EXT: 146 d3dBlendOp = D3DBLENDOP_MIN; 147 break; 148 case GL_MAX_EXT: 149 d3dBlendOp = D3DBLENDOP_MAX; 150 break; 151 default: 152 UNREACHABLE(); 153 } 154 155 return d3dBlendOp; 156 } 157 158 D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) 159 { 160 D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; 161 162 switch (stencilOp) 163 { 164 case GL_ZERO: 165 d3dStencilOp = D3DSTENCILOP_ZERO; 166 break; 167 case GL_KEEP: 168 d3dStencilOp = D3DSTENCILOP_KEEP; 169 break; 170 case GL_REPLACE: 171 d3dStencilOp = D3DSTENCILOP_REPLACE; 172 break; 173 case GL_INCR: 174 d3dStencilOp = D3DSTENCILOP_INCRSAT; 175 break; 176 case GL_DECR: 177 d3dStencilOp = D3DSTENCILOP_DECRSAT; 178 break; 179 case GL_INVERT: 180 d3dStencilOp = D3DSTENCILOP_INVERT; 181 break; 182 case GL_INCR_WRAP: 183 d3dStencilOp = D3DSTENCILOP_INCR; 184 break; 185 case GL_DECR_WRAP: 186 d3dStencilOp = D3DSTENCILOP_DECR; 187 break; 188 default: 189 UNREACHABLE(); 190 } 191 192 return d3dStencilOp; 193 } 194 195 D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) 196 { 197 D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; 198 199 switch (wrap) 200 { 201 case GL_REPEAT: 202 d3dWrap = D3DTADDRESS_WRAP; 203 break; 204 case GL_CLAMP_TO_EDGE: 205 d3dWrap = D3DTADDRESS_CLAMP; 206 break; 207 case GL_CLAMP_TO_BORDER: 208 d3dWrap = D3DTADDRESS_BORDER; 209 break; 210 case GL_MIRRORED_REPEAT: 211 d3dWrap = D3DTADDRESS_MIRROR; 212 break; 213 default: 214 UNREACHABLE(); 215 } 216 217 return d3dWrap; 218 } 219 220 D3DCULL ConvertCullMode(gl::CullFaceMode cullFace, GLenum frontFace) 221 { 222 D3DCULL cull = D3DCULL_CCW; 223 switch (cullFace) 224 { 225 case gl::CullFaceMode::Front: 226 cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); 227 break; 228 case gl::CullFaceMode::Back: 229 cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); 230 break; 231 case gl::CullFaceMode::FrontAndBack: 232 cull = D3DCULL_NONE; // culling will be handled during draw 233 break; 234 default: 235 UNREACHABLE(); 236 } 237 238 return cull; 239 } 240 241 D3DCUBEMAP_FACES ConvertCubeFace(gl::TextureTarget cubeFace) 242 { 243 D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; 244 245 switch (cubeFace) 246 { 247 case gl::TextureTarget::CubeMapPositiveX: 248 face = D3DCUBEMAP_FACE_POSITIVE_X; 249 break; 250 case gl::TextureTarget::CubeMapNegativeX: 251 face = D3DCUBEMAP_FACE_NEGATIVE_X; 252 break; 253 case gl::TextureTarget::CubeMapPositiveY: 254 face = D3DCUBEMAP_FACE_POSITIVE_Y; 255 break; 256 case gl::TextureTarget::CubeMapNegativeY: 257 face = D3DCUBEMAP_FACE_NEGATIVE_Y; 258 break; 259 case gl::TextureTarget::CubeMapPositiveZ: 260 face = D3DCUBEMAP_FACE_POSITIVE_Z; 261 break; 262 case gl::TextureTarget::CubeMapNegativeZ: 263 face = D3DCUBEMAP_FACE_NEGATIVE_Z; 264 break; 265 default: 266 UNREACHABLE(); 267 } 268 269 return face; 270 } 271 272 DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) 273 { 274 return (red ? D3DCOLORWRITEENABLE_RED : 0) | (green ? D3DCOLORWRITEENABLE_GREEN : 0) | 275 (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); 276 } 277 278 D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) 279 { 280 if (maxAnisotropy > 1.0f) 281 { 282 return D3DTEXF_ANISOTROPIC; 283 } 284 285 D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; 286 switch (magFilter) 287 { 288 case GL_NEAREST: 289 d3dMagFilter = D3DTEXF_POINT; 290 break; 291 case GL_LINEAR: 292 d3dMagFilter = D3DTEXF_LINEAR; 293 break; 294 default: 295 UNREACHABLE(); 296 } 297 298 return d3dMagFilter; 299 } 300 301 void ConvertMinFilter(GLenum minFilter, 302 D3DTEXTUREFILTERTYPE *d3dMinFilter, 303 D3DTEXTUREFILTERTYPE *d3dMipFilter, 304 float *d3dLodBias, 305 float maxAnisotropy, 306 size_t baseLevel) 307 { 308 switch (minFilter) 309 { 310 case GL_NEAREST: 311 *d3dMinFilter = D3DTEXF_POINT; 312 *d3dMipFilter = D3DTEXF_NONE; 313 break; 314 case GL_LINEAR: 315 *d3dMinFilter = D3DTEXF_LINEAR; 316 *d3dMipFilter = D3DTEXF_NONE; 317 break; 318 case GL_NEAREST_MIPMAP_NEAREST: 319 *d3dMinFilter = D3DTEXF_POINT; 320 *d3dMipFilter = D3DTEXF_POINT; 321 break; 322 case GL_LINEAR_MIPMAP_NEAREST: 323 *d3dMinFilter = D3DTEXF_LINEAR; 324 *d3dMipFilter = D3DTEXF_POINT; 325 break; 326 case GL_NEAREST_MIPMAP_LINEAR: 327 *d3dMinFilter = D3DTEXF_POINT; 328 *d3dMipFilter = D3DTEXF_LINEAR; 329 break; 330 case GL_LINEAR_MIPMAP_LINEAR: 331 *d3dMinFilter = D3DTEXF_LINEAR; 332 *d3dMipFilter = D3DTEXF_LINEAR; 333 break; 334 default: 335 *d3dMinFilter = D3DTEXF_POINT; 336 *d3dMipFilter = D3DTEXF_NONE; 337 UNREACHABLE(); 338 } 339 340 // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work 341 // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the 342 // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to 343 // ensure that only the base mip level is sampled. 344 if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE) 345 { 346 *d3dMipFilter = D3DTEXF_POINT; 347 *d3dLodBias = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); 348 } 349 else 350 { 351 *d3dLodBias = 0.0f; 352 } 353 354 if (maxAnisotropy > 1.0f) 355 { 356 *d3dMinFilter = D3DTEXF_ANISOTROPIC; 357 } 358 } 359 360 D3DQUERYTYPE ConvertQueryType(gl::QueryType type) 361 { 362 switch (type) 363 { 364 case gl::QueryType::AnySamples: 365 case gl::QueryType::AnySamplesConservative: 366 return D3DQUERYTYPE_OCCLUSION; 367 case gl::QueryType::CommandsCompleted: 368 return D3DQUERYTYPE_EVENT; 369 default: 370 UNREACHABLE(); 371 return static_cast<D3DQUERYTYPE>(0); 372 } 373 } 374 375 D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) 376 { 377 return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; 378 } 379 380 } // namespace gl_d3d9 381 382 namespace d3d9_gl 383 { 384 385 unsigned int GetReservedVaryingVectors() 386 { 387 // We reserve two registers for "dx_Position" and "gl_Position". The spec says they 388 // don't count towards the varying limit, so we must make space for them. We also 389 // reserve the last register since it can only pass a PSIZE, and not any arbitrary 390 // varying. 391 return 3; 392 } 393 394 unsigned int GetReservedVertexUniformVectors() 395 { 396 return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange. 397 } 398 399 unsigned int GetReservedFragmentUniformVectors() 400 { 401 return 4; // dx_ViewCoords, dx_DepthFront, dx_DepthRange, dx_FragCoordoffset. 402 } 403 404 GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) 405 { 406 return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; 407 } 408 409 bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) 410 { 411 GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat; 412 GLenum convertedFormat = gl::GetSizedInternalFormatInfo(internalFormat).format; 413 return convertedFormat == format; 414 } 415 416 static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, 417 IDirect3D9 *d3d9, 418 D3DDEVTYPE deviceType, 419 UINT adapter, 420 D3DFORMAT adapterFormat) 421 { 422 gl::TextureCaps textureCaps; 423 424 const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); 425 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); 426 427 if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) 428 { 429 if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) 430 { 431 textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat( 432 adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); 433 } 434 else 435 { 436 textureCaps.texturable = 437 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, 438 D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && 439 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, 440 D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); 441 if (textureCaps.texturable && (formatInfo.colorEncoding == GL_SRGB)) 442 { 443 textureCaps.texturable = 444 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 445 D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE, 446 d3dFormatInfo.texFormat)) && 447 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 448 D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_CUBETEXTURE, 449 d3dFormatInfo.texFormat)); 450 } 451 } 452 453 textureCaps.filterable = SUCCEEDED( 454 d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, 455 D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); 456 } 457 458 if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN) 459 { 460 textureCaps.textureAttachment = SUCCEEDED( 461 d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, 462 D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); 463 if (textureCaps.textureAttachment && (formatInfo.colorEncoding == GL_SRGB)) 464 { 465 textureCaps.textureAttachment = SUCCEEDED(d3d9->CheckDeviceFormat( 466 adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE, 467 d3dFormatInfo.renderFormat)); 468 } 469 470 if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && 471 !textureCaps.textureAttachment) 472 { 473 textureCaps.textureAttachment = SUCCEEDED( 474 d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, 475 D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); 476 } 477 textureCaps.renderbuffer = textureCaps.textureAttachment; 478 textureCaps.blendable = textureCaps.renderbuffer; 479 480 textureCaps.sampleCounts.insert(1); 481 for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) 482 { 483 D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); 484 485 HRESULT result = d3d9->CheckDeviceMultiSampleType( 486 adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr); 487 if (SUCCEEDED(result)) 488 { 489 textureCaps.sampleCounts.insert(i); 490 } 491 } 492 } 493 494 return textureCaps; 495 } 496 497 void GenerateCaps(IDirect3D9 *d3d9, 498 IDirect3DDevice9 *device, 499 D3DDEVTYPE deviceType, 500 UINT adapter, 501 gl::Caps *caps, 502 gl::TextureCapsMap *textureCapsMap, 503 gl::Extensions *extensions, 504 gl::Limitations *limitations) 505 { 506 D3DCAPS9 deviceCaps; 507 if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) 508 { 509 // Can't continue with out device caps 510 return; 511 } 512 513 D3DDISPLAYMODE currentDisplayMode; 514 d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); 515 516 GLuint maxSamples = 0; 517 for (GLenum internalFormat : gl::GetAllSizedInternalFormats()) 518 { 519 gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType, 520 adapter, currentDisplayMode.Format); 521 textureCapsMap->insert(internalFormat, textureCaps); 522 523 maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); 524 } 525 526 // GL core feature limits 527 caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); 528 529 // 3D textures are unimplemented in D3D9 530 caps->max3DTextureSize = 1; 531 532 // Only one limit in GL, use the minimum dimension 533 caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); 534 535 // D3D treats cube maps as a special case of 2D textures 536 caps->maxCubeMapTextureSize = caps->max2DTextureSize; 537 538 // Array textures are not available in D3D9 539 caps->maxArrayTextureLayers = 1; 540 541 // ES3-only feature 542 caps->maxLODBias = 0.0f; 543 544 // No specific limits on render target size, maximum 2D texture size is equivalent 545 caps->maxRenderbufferSize = caps->max2DTextureSize; 546 547 // Draw buffers are not supported in D3D9 548 caps->maxDrawBuffers = 1; 549 caps->maxColorAttachments = 1; 550 551 // No specific limits on viewport size, maximum 2D texture size is equivalent 552 caps->maxViewportWidth = caps->max2DTextureSize; 553 caps->maxViewportHeight = caps->maxViewportWidth; 554 555 // Point size is clamped to 1.0f when the shader model is less than 3 556 caps->minAliasedPointSize = 1.0f; 557 caps->maxAliasedPointSize = 558 ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize 559 : 1.0f); 560 561 // Wide lines not supported 562 caps->minAliasedLineWidth = 1.0f; 563 caps->maxAliasedLineWidth = 1.0f; 564 565 // Primitive count limits (unused in ES2) 566 caps->maxElementsIndices = 0; 567 caps->maxElementsVertices = 0; 568 569 // Program and shader binary formats (no supported shader binary formats) 570 caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); 571 572 caps->vertexHighpFloat.setIEEEFloat(); 573 caps->vertexMediumpFloat.setIEEEFloat(); 574 caps->vertexLowpFloat.setIEEEFloat(); 575 caps->fragmentHighpFloat.setIEEEFloat(); 576 caps->fragmentMediumpFloat.setIEEEFloat(); 577 caps->fragmentLowpFloat.setIEEEFloat(); 578 579 // Some (most) hardware only supports single-precision floating-point numbers, 580 // which can accurately represent integers up to +/-16777216 581 caps->vertexHighpInt.setSimulatedInt(24); 582 caps->vertexMediumpInt.setSimulatedInt(24); 583 caps->vertexLowpInt.setSimulatedInt(24); 584 caps->fragmentHighpInt.setSimulatedInt(24); 585 caps->fragmentMediumpInt.setSimulatedInt(24); 586 caps->fragmentLowpInt.setSimulatedInt(24); 587 588 // WaitSync is ES3-only, set to zero 589 caps->maxServerWaitTimeout = 0; 590 591 // Vertex shader limits 592 caps->maxVertexAttributes = 16; 593 // Vertex Attrib Binding not supported. 594 caps->maxVertexAttribBindings = caps->maxVertexAttributes; 595 596 const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; 597 caps->maxVertexUniformVectors = 598 MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors(); 599 caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4; 600 601 caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0; 602 603 // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE. 604 const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors(); 605 const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors(); 606 caps->maxVertexOutputComponents = 607 ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 608 : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 609 4; 610 611 // Only Direct3D 10 ready devices support all the necessary vertex texture formats. 612 // We test this using D3D9 by checking support for the R16F format. 613 if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && 614 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, 615 D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, 616 D3DFMT_R16F))) 617 { 618 const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; 619 caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; 620 } 621 else 622 { 623 caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0; 624 } 625 626 // Fragment shader limits 627 const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; 628 const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; 629 caps->maxFragmentUniformVectors = 630 ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 631 : MAX_PIXEL_CONSTANT_VECTORS_SM2) - 632 GetReservedFragmentUniformVectors(); 633 caps->maxShaderUniformComponents[gl::ShaderType::Fragment] = 634 caps->maxFragmentUniformVectors * 4; 635 caps->maxShaderUniformBlocks[gl::ShaderType::Fragment] = 0; 636 caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; 637 caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 16; 638 caps->minProgramTexelOffset = 0; 639 caps->maxProgramTexelOffset = 0; 640 641 // Aggregate shader limits (unused in ES2) 642 caps->maxUniformBufferBindings = 0; 643 caps->maxUniformBlockSize = 0; 644 caps->uniformBufferOffsetAlignment = 0; 645 caps->maxCombinedUniformBlocks = 0; 646 caps->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex] = 0; 647 caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0; 648 caps->maxVaryingComponents = 0; 649 650 // Aggregate shader limits 651 caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; 652 caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] + 653 caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment]; 654 655 // Transform feedback limits 656 caps->maxTransformFeedbackInterleavedComponents = 0; 657 caps->maxTransformFeedbackSeparateAttributes = 0; 658 caps->maxTransformFeedbackSeparateComponents = 0; 659 660 // Multisample limits 661 caps->maxSamples = maxSamples; 662 663 // GL extension support 664 extensions->setTextureExtensionSupport(*textureCapsMap); 665 extensions->elementIndexUintOES = deviceCaps.MaxVertexIndex >= (1 << 16); 666 extensions->getProgramBinaryOES = true; 667 extensions->rgb8Rgba8OES = true; 668 extensions->readFormatBgraEXT = true; 669 extensions->pixelBufferObjectNV = false; 670 extensions->mapbufferOES = false; 671 extensions->mapBufferRangeEXT = false; 672 673 // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture 674 // allows for that so we can't implement full support with the D3D9 back end. 675 extensions->depthTextureOES = false; 676 677 // textureRgEXT is emulated and not performant. 678 extensions->textureRgEXT = false; 679 680 // GL_KHR_parallel_shader_compile 681 extensions->parallelShaderCompileKHR = true; 682 683 D3DADAPTER_IDENTIFIER9 adapterId = {}; 684 if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) 685 { 686 // ATI cards on XP have problems with non-power-of-two textures. 687 extensions->textureNpotOES = 688 !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && 689 !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && 690 !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && 691 !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId)); 692 693 // Disable depth texture support on AMD cards (See ANGLE issue 839) 694 if (IsAMD(adapterId.VendorId)) 695 { 696 extensions->depthTextureANGLE = false; 697 extensions->depthTextureOES = false; 698 } 699 } 700 else 701 { 702 extensions->textureNpotOES = false; 703 } 704 705 extensions->drawBuffersEXT = false; 706 extensions->textureStorageEXT = true; 707 708 // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per 709 // the spec 710 extensions->textureFilterAnisotropicEXT = 711 (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; 712 caps->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy); 713 714 // Check occlusion query support by trying to create one 715 IDirect3DQuery9 *occlusionQuery = nullptr; 716 extensions->occlusionQueryBooleanEXT = 717 SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; 718 SafeRelease(occlusionQuery); 719 720 // Check event query support by trying to create one 721 IDirect3DQuery9 *eventQuery = nullptr; 722 extensions->fenceNV = 723 SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; 724 SafeRelease(eventQuery); 725 726 extensions->disjointTimerQueryEXT = false; 727 extensions->robustnessEXT = true; 728 // It seems that only DirectX 10 and higher enforce the well-defined behavior of always 729 // returning zero values when out-of-bounds reads. See 730 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt 731 extensions->robustBufferAccessBehaviorKHR = false; 732 extensions->blendMinmaxEXT = true; 733 // Although according to 734 // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware 735 // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide 736 // correct blending result in reality. As a result of some regression reports by client app, we 737 // decided to turn floatBlendEXT on for D3D9 738 extensions->floatBlendEXT = true; 739 extensions->framebufferBlitANGLE = true; 740 extensions->framebufferMultisampleANGLE = true; 741 extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); 742 // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT 743 // extension 744 extensions->instancedArraysEXT = false; 745 extensions->packReverseRowOrderANGLE = true; 746 extensions->standardDerivativesOES = 747 (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; 748 extensions->shaderTextureLodEXT = true; 749 extensions->fragDepthEXT = true; 750 extensions->textureUsageANGLE = true; 751 extensions->translatedShaderSourceANGLE = true; 752 extensions->fboRenderMipmapOES = true; 753 extensions->discardFramebufferEXT = false; // It would be valid to set this to true, since 754 // glDiscardFramebufferEXT is just a hint 755 extensions->colorBufferFloatEXT = false; 756 extensions->debugMarkerEXT = true; 757 extensions->EGLImageOES = true; 758 extensions->EGLImageExternalOES = true; 759 extensions->unpackSubimageEXT = true; 760 extensions->packSubimageNV = true; 761 extensions->syncQueryCHROMIUM = extensions->fenceNV; 762 extensions->copyTextureCHROMIUM = true; 763 extensions->textureBorderClampOES = true; 764 extensions->videoTextureWEBGL = true; 765 766 // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil 767 // state. 768 limitations->noSeparateStencilRefsAndMasks = true; 769 770 // D3D9 shader models have limited support for looping, so the Appendix A 771 // index/loop limitations are necessary. Workarounds that are needed to 772 // support dynamic indexing of vectors on HLSL also don't work on D3D9. 773 limitations->shadersRequireIndexedLoopValidation = true; 774 775 // D3D9 cannot support constant color and alpha blend funcs together 776 limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; 777 778 // D3D9 cannot support unclamped constant blend color 779 limitations->noUnclampedBlendColor = true; 780 781 // D3D9 cannot support packing more than one variable to a single varying. 782 // TODO(jmadill): Implement more sophisticated component packing in D3D9. 783 limitations->noFlexibleVaryingPacking = true; 784 785 // D3D9 does not support vertex attribute aliasing 786 limitations->noVertexAttributeAliasing = true; 787 788 // D3D9 does not support compressed textures where the base mip level is not a multiple of 4 789 limitations->compressedBaseMipLevelMultipleOfFour = true; 790 } 791 792 } // namespace d3d9_gl 793 794 namespace d3d9 795 { 796 797 GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) 798 { 799 const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); 800 GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; 801 GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; 802 return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); 803 } 804 805 void MakeValidSize(bool isImage, 806 D3DFORMAT format, 807 GLsizei *requestWidth, 808 GLsizei *requestHeight, 809 int *levelOffset) 810 { 811 const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); 812 813 int upsampleCount = 0; 814 // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. 815 if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) || 816 *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight)) 817 { 818 while (*requestWidth % d3dFormatInfo.blockWidth != 0 || 819 *requestHeight % d3dFormatInfo.blockHeight != 0) 820 { 821 *requestWidth <<= 1; 822 *requestHeight <<= 1; 823 upsampleCount++; 824 } 825 } 826 *levelOffset = upsampleCount; 827 } 828 829 void InitializeFeatures(angle::FeaturesD3D *features) 830 { 831 ANGLE_FEATURE_CONDITION(features, mrtPerfWorkaround, true); 832 ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUpload, false); 833 ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUploadOn128bitFormats, false); 834 ANGLE_FEATURE_CONDITION(features, useInstancedPointSpriteEmulation, false); 835 836 // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. 837 ANGLE_FEATURE_CONDITION(features, expandIntegerPowExpressions, true); 838 839 // crbug.com/1011627 Turn this on for D3D9. 840 ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true); 841 } 842 843 } // namespace d3d9 844 845 } // namespace rx