tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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, &currentDisplayMode);
    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