diff options
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp new file mode 100644 index 0000000000..79e5c9cb06 --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d9/renderer9_utils.cpp @@ -0,0 +1,845 @@ +// +// Copyright 2002 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// renderer9_utils.cpp: Conversion functions and other utility routines +// specific to the D3D9 renderer. + +#include "libANGLE/renderer/d3d/d3d9/renderer9_utils.h" + +#include "common/debug.h" +#include "common/mathutil.h" + +#include "libANGLE/formatutils.h" +#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h" +#include "libANGLE/renderer/d3d/d3d9/formatutils9.h" +#include "libANGLE/renderer/driver_utils.h" +#include "platform/FeaturesD3D_autogen.h" +#include "platform/PlatformMethods.h" + +#include "third_party/systeminfo/SystemInfo.h" + +namespace rx +{ + +namespace gl_d3d9 +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: + d3dComp = D3DCMP_NEVER; + break; + case GL_ALWAYS: + d3dComp = D3DCMP_ALWAYS; + break; + case GL_LESS: + d3dComp = D3DCMP_LESS; + break; + case GL_LEQUAL: + d3dComp = D3DCMP_LESSEQUAL; + break; + case GL_EQUAL: + d3dComp = D3DCMP_EQUAL; + break; + case GL_GREATER: + d3dComp = D3DCMP_GREATER; + break; + case GL_GEQUAL: + d3dComp = D3DCMP_GREATEREQUAL; + break; + case GL_NOTEQUAL: + d3dComp = D3DCMP_NOTEQUAL; + break; + default: + UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::ColorF color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), gl::unorm<8>(color.green), + gl::unorm<8>(color.blue), gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: + d3dBlend = D3DBLEND_ZERO; + break; + case GL_ONE: + d3dBlend = D3DBLEND_ONE; + break; + case GL_SRC_COLOR: + d3dBlend = D3DBLEND_SRCCOLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + d3dBlend = D3DBLEND_INVSRCCOLOR; + break; + case GL_DST_COLOR: + d3dBlend = D3DBLEND_DESTCOLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + d3dBlend = D3DBLEND_INVDESTCOLOR; + break; + case GL_SRC_ALPHA: + d3dBlend = D3DBLEND_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + d3dBlend = D3DBLEND_INVSRCALPHA; + break; + case GL_DST_ALPHA: + d3dBlend = D3DBLEND_DESTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + d3dBlend = D3DBLEND_INVDESTALPHA; + break; + case GL_CONSTANT_COLOR: + d3dBlend = D3DBLEND_BLENDFACTOR; + break; + case GL_ONE_MINUS_CONSTANT_COLOR: + d3dBlend = D3DBLEND_INVBLENDFACTOR; + break; + case GL_CONSTANT_ALPHA: + d3dBlend = D3DBLEND_BLENDFACTOR; + break; + case GL_ONE_MINUS_CONSTANT_ALPHA: + d3dBlend = D3DBLEND_INVBLENDFACTOR; + break; + case GL_SRC_ALPHA_SATURATE: + d3dBlend = D3DBLEND_SRCALPHASAT; + break; + default: + UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: + d3dBlendOp = D3DBLENDOP_ADD; + break; + case GL_FUNC_SUBTRACT: + d3dBlendOp = D3DBLENDOP_SUBTRACT; + break; + case GL_FUNC_REVERSE_SUBTRACT: + d3dBlendOp = D3DBLENDOP_REVSUBTRACT; + break; + case GL_MIN_EXT: + d3dBlendOp = D3DBLENDOP_MIN; + break; + case GL_MAX_EXT: + d3dBlendOp = D3DBLENDOP_MAX; + break; + default: + UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: + d3dStencilOp = D3DSTENCILOP_ZERO; + break; + case GL_KEEP: + d3dStencilOp = D3DSTENCILOP_KEEP; + break; + case GL_REPLACE: + d3dStencilOp = D3DSTENCILOP_REPLACE; + break; + case GL_INCR: + d3dStencilOp = D3DSTENCILOP_INCRSAT; + break; + case GL_DECR: + d3dStencilOp = D3DSTENCILOP_DECRSAT; + break; + case GL_INVERT: + d3dStencilOp = D3DSTENCILOP_INVERT; + break; + case GL_INCR_WRAP: + d3dStencilOp = D3DSTENCILOP_INCR; + break; + case GL_DECR_WRAP: + d3dStencilOp = D3DSTENCILOP_DECR; + break; + default: + UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: + d3dWrap = D3DTADDRESS_WRAP; + break; + case GL_CLAMP_TO_EDGE: + d3dWrap = D3DTADDRESS_CLAMP; + break; + case GL_CLAMP_TO_BORDER: + d3dWrap = D3DTADDRESS_BORDER; + break; + case GL_MIRRORED_REPEAT: + d3dWrap = D3DTADDRESS_MIRROR; + break; + default: + UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(gl::CullFaceMode cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case gl::CullFaceMode::Front: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case gl::CullFaceMode::Back: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case gl::CullFaceMode::FrontAndBack: + cull = D3DCULL_NONE; // culling will be handled during draw + break; + default: + UNREACHABLE(); + } + + return cull; +} + +D3DCUBEMAP_FACES ConvertCubeFace(gl::TextureTarget cubeFace) +{ + D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X; + + switch (cubeFace) + { + case gl::TextureTarget::CubeMapPositiveX: + face = D3DCUBEMAP_FACE_POSITIVE_X; + break; + case gl::TextureTarget::CubeMapNegativeX: + face = D3DCUBEMAP_FACE_NEGATIVE_X; + break; + case gl::TextureTarget::CubeMapPositiveY: + face = D3DCUBEMAP_FACE_POSITIVE_Y; + break; + case gl::TextureTarget::CubeMapNegativeY: + face = D3DCUBEMAP_FACE_NEGATIVE_Y; + break; + case gl::TextureTarget::CubeMapPositiveZ: + face = D3DCUBEMAP_FACE_POSITIVE_Z; + break; + case gl::TextureTarget::CubeMapNegativeZ: + face = D3DCUBEMAP_FACE_NEGATIVE_Z; + break; + default: + UNREACHABLE(); + } + + return face; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy) +{ + if (maxAnisotropy > 1.0f) + { + return D3DTEXF_ANISOTROPIC; + } + + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: + d3dMagFilter = D3DTEXF_POINT; + break; + case GL_LINEAR: + d3dMagFilter = D3DTEXF_LINEAR; + break; + default: + UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, + D3DTEXTUREFILTERTYPE *d3dMinFilter, + D3DTEXTUREFILTERTYPE *d3dMipFilter, + float *d3dLodBias, + float maxAnisotropy, + size_t baseLevel) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } + + // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work + // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the + // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to + // ensure that only the base mip level is sampled. + if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE) + { + *d3dMipFilter = D3DTEXF_POINT; + *d3dLodBias = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS); + } + else + { + *d3dLodBias = 0.0f; + } + + if (maxAnisotropy > 1.0f) + { + *d3dMinFilter = D3DTEXF_ANISOTROPIC; + } +} + +D3DQUERYTYPE ConvertQueryType(gl::QueryType type) +{ + switch (type) + { + case gl::QueryType::AnySamples: + case gl::QueryType::AnySamplesConservative: + return D3DQUERYTYPE_OCCLUSION; + case gl::QueryType::CommandsCompleted: + return D3DQUERYTYPE_EVENT; + default: + UNREACHABLE(); + return static_cast<D3DQUERYTYPE>(0); + } +} + +D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) +{ + return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE; +} + +} // namespace gl_d3d9 + +namespace d3d9_gl +{ + +unsigned int GetReservedVaryingVectors() +{ + // We reserve two registers for "dx_Position" and "gl_Position". The spec says they + // don't count towards the varying limit, so we must make space for them. We also + // reserve the last register since it can only pass a PSIZE, and not any arbitrary + // varying. + return 3; +} + +unsigned int GetReservedVertexUniformVectors() +{ + return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange. +} + +unsigned int GetReservedFragmentUniformVectors() +{ + return 4; // dx_ViewCoords, dx_DepthFront, dx_DepthRange, dx_FragCoordoffset. +} + +GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type) +{ + return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0; +} + +bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format) +{ + GLenum internalFormat = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat; + GLenum convertedFormat = gl::GetSizedInternalFormatInfo(internalFormat).format; + return convertedFormat == format; +} + +static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat, + IDirect3D9 *d3d9, + D3DDEVTYPE deviceType, + UINT adapter, + D3DFORMAT adapterFormat) +{ + gl::TextureCaps textureCaps; + + const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat); + const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat); + + if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN) + { + if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) + { + textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat( + adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + else + { + textureCaps.texturable = + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, + D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0, + D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat)); + if (textureCaps.texturable && (formatInfo.colorEncoding == GL_SRGB)) + { + textureCaps.texturable = + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, + D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE, + d3dFormatInfo.texFormat)) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, + D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_CUBETEXTURE, + d3dFormatInfo.texFormat)); + } + } + + textureCaps.filterable = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, + D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)); + } + + if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN) + { + textureCaps.textureAttachment = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, + D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + if (textureCaps.textureAttachment && (formatInfo.colorEncoding == GL_SRGB)) + { + textureCaps.textureAttachment = SUCCEEDED(d3d9->CheckDeviceFormat( + adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE, + d3dFormatInfo.renderFormat)); + } + + if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && + !textureCaps.textureAttachment) + { + textureCaps.textureAttachment = SUCCEEDED( + d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, + D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat)); + } + textureCaps.renderbuffer = textureCaps.textureAttachment; + textureCaps.blendable = textureCaps.renderbuffer; + + textureCaps.sampleCounts.insert(1); + for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++) + { + D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i); + + HRESULT result = d3d9->CheckDeviceMultiSampleType( + adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr); + if (SUCCEEDED(result)) + { + textureCaps.sampleCounts.insert(i); + } + } + } + + return textureCaps; +} + +void GenerateCaps(IDirect3D9 *d3d9, + IDirect3DDevice9 *device, + D3DDEVTYPE deviceType, + UINT adapter, + gl::Caps *caps, + gl::TextureCapsMap *textureCapsMap, + gl::Extensions *extensions, + gl::Limitations *limitations) +{ + D3DCAPS9 deviceCaps; + if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) + { + // Can't continue with out device caps + return; + } + + D3DDISPLAYMODE currentDisplayMode; + d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); + + GLuint maxSamples = 0; + for (GLenum internalFormat : gl::GetAllSizedInternalFormats()) + { + gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType, + adapter, currentDisplayMode.Format); + textureCapsMap->insert(internalFormat, textureCaps); + + maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); + } + + // GL core feature limits + caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); + + // 3D textures are unimplemented in D3D9 + caps->max3DTextureSize = 1; + + // Only one limit in GL, use the minimum dimension + caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight); + + // D3D treats cube maps as a special case of 2D textures + caps->maxCubeMapTextureSize = caps->max2DTextureSize; + + // Array textures are not available in D3D9 + caps->maxArrayTextureLayers = 1; + + // ES3-only feature + caps->maxLODBias = 0.0f; + + // No specific limits on render target size, maximum 2D texture size is equivalent + caps->maxRenderbufferSize = caps->max2DTextureSize; + + // Draw buffers are not supported in D3D9 + caps->maxDrawBuffers = 1; + caps->maxColorAttachments = 1; + + // No specific limits on viewport size, maximum 2D texture size is equivalent + caps->maxViewportWidth = caps->max2DTextureSize; + caps->maxViewportHeight = caps->maxViewportWidth; + + // Point size is clamped to 1.0f when the shader model is less than 3 + caps->minAliasedPointSize = 1.0f; + caps->maxAliasedPointSize = + ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize + : 1.0f); + + // Wide lines not supported + caps->minAliasedLineWidth = 1.0f; + caps->maxAliasedLineWidth = 1.0f; + + // Primitive count limits (unused in ES2) + caps->maxElementsIndices = 0; + caps->maxElementsVertices = 0; + + // Program and shader binary formats (no supported shader binary formats) + caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE); + + caps->vertexHighpFloat.setIEEEFloat(); + caps->vertexMediumpFloat.setIEEEFloat(); + caps->vertexLowpFloat.setIEEEFloat(); + caps->fragmentHighpFloat.setIEEEFloat(); + caps->fragmentMediumpFloat.setIEEEFloat(); + caps->fragmentLowpFloat.setIEEEFloat(); + + // Some (most) hardware only supports single-precision floating-point numbers, + // which can accurately represent integers up to +/-16777216 + caps->vertexHighpInt.setSimulatedInt(24); + caps->vertexMediumpInt.setSimulatedInt(24); + caps->vertexLowpInt.setSimulatedInt(24); + caps->fragmentHighpInt.setSimulatedInt(24); + caps->fragmentMediumpInt.setSimulatedInt(24); + caps->fragmentLowpInt.setSimulatedInt(24); + + // WaitSync is ES3-only, set to zero + caps->maxServerWaitTimeout = 0; + + // Vertex shader limits + caps->maxVertexAttributes = 16; + // Vertex Attrib Binding not supported. + caps->maxVertexAttribBindings = caps->maxVertexAttributes; + + const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; + caps->maxVertexUniformVectors = + MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors(); + caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4; + + caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0; + + // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE. + const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors(); + const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors(); + caps->maxVertexOutputComponents = + ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 + : MAX_VERTEX_OUTPUT_VECTORS_SM2) * + 4; + + // Only Direct3D 10 ready devices support all the necessary vertex texture formats. + // We test this using D3D9 by checking support for the R16F format. + if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) && + SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format, + D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, + D3DFMT_R16F))) + { + const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3 = 4; + caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3; + } + else + { + caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0; + } + + // Fragment shader limits + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224; + const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32; + caps->maxFragmentUniformVectors = + ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3 + : MAX_PIXEL_CONSTANT_VECTORS_SM2) - + GetReservedFragmentUniformVectors(); + caps->maxShaderUniformComponents[gl::ShaderType::Fragment] = + caps->maxFragmentUniformVectors * 4; + caps->maxShaderUniformBlocks[gl::ShaderType::Fragment] = 0; + caps->maxFragmentInputComponents = caps->maxVertexOutputComponents; + caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 16; + caps->minProgramTexelOffset = 0; + caps->maxProgramTexelOffset = 0; + + // Aggregate shader limits (unused in ES2) + caps->maxUniformBufferBindings = 0; + caps->maxUniformBlockSize = 0; + caps->uniformBufferOffsetAlignment = 0; + caps->maxCombinedUniformBlocks = 0; + caps->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex] = 0; + caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0; + caps->maxVaryingComponents = 0; + + // Aggregate shader limits + caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4; + caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] + + caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment]; + + // Transform feedback limits + caps->maxTransformFeedbackInterleavedComponents = 0; + caps->maxTransformFeedbackSeparateAttributes = 0; + caps->maxTransformFeedbackSeparateComponents = 0; + + // Multisample limits + caps->maxSamples = maxSamples; + + // GL extension support + extensions->setTextureExtensionSupport(*textureCapsMap); + extensions->elementIndexUintOES = deviceCaps.MaxVertexIndex >= (1 << 16); + extensions->getProgramBinaryOES = true; + extensions->rgb8Rgba8OES = true; + extensions->readFormatBgraEXT = true; + extensions->pixelBufferObjectNV = false; + extensions->mapbufferOES = false; + extensions->mapBufferRangeEXT = false; + + // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture + // allows for that so we can't implement full support with the D3D9 back end. + extensions->depthTextureOES = false; + + // textureRgEXT is emulated and not performant. + extensions->textureRgEXT = false; + + // GL_KHR_parallel_shader_compile + extensions->parallelShaderCompileKHR = true; + + D3DADAPTER_IDENTIFIER9 adapterId = {}; + if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) + { + // ATI cards on XP have problems with non-power-of-two textures. + extensions->textureNpotOES = + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && + !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && + !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId)); + + // Disable depth texture support on AMD cards (See ANGLE issue 839) + if (IsAMD(adapterId.VendorId)) + { + extensions->depthTextureANGLE = false; + extensions->depthTextureOES = false; + } + } + else + { + extensions->textureNpotOES = false; + } + + extensions->drawBuffersEXT = false; + extensions->textureStorageEXT = true; + + // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per + // the spec + extensions->textureFilterAnisotropicEXT = + (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2; + caps->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy); + + // Check occlusion query support by trying to create one + IDirect3DQuery9 *occlusionQuery = nullptr; + extensions->occlusionQueryBooleanEXT = + SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; + SafeRelease(occlusionQuery); + + // Check event query support by trying to create one + IDirect3DQuery9 *eventQuery = nullptr; + extensions->fenceNV = + SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; + SafeRelease(eventQuery); + + extensions->disjointTimerQueryEXT = false; + extensions->robustnessEXT = true; + // It seems that only DirectX 10 and higher enforce the well-defined behavior of always + // returning zero values when out-of-bounds reads. See + // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt + extensions->robustBufferAccessBehaviorKHR = false; + extensions->blendMinmaxEXT = true; + // Although according to + // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware + // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide + // correct blending result in reality. As a result of some regression reports by client app, we + // decided to turn floatBlendEXT on for D3D9 + extensions->floatBlendEXT = true; + extensions->framebufferBlitANGLE = true; + extensions->framebufferMultisampleANGLE = true; + extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0); + // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT + // extension + extensions->instancedArraysEXT = false; + extensions->packReverseRowOrderANGLE = true; + extensions->standardDerivativesOES = + (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0; + extensions->shaderTextureLodEXT = true; + extensions->fragDepthEXT = true; + extensions->textureUsageANGLE = true; + extensions->translatedShaderSourceANGLE = true; + extensions->fboRenderMipmapOES = true; + extensions->discardFramebufferEXT = false; // It would be valid to set this to true, since + // glDiscardFramebufferEXT is just a hint + extensions->colorBufferFloatEXT = false; + extensions->debugMarkerEXT = true; + extensions->EGLImageOES = true; + extensions->EGLImageExternalOES = true; + extensions->unpackSubimageEXT = true; + extensions->packSubimageNV = true; + extensions->syncQueryCHROMIUM = extensions->fenceNV; + extensions->copyTextureCHROMIUM = true; + extensions->textureBorderClampOES = true; + extensions->videoTextureWEBGL = true; + + // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil + // state. + limitations->noSeparateStencilRefsAndMasks = true; + + // D3D9 shader models have limited support for looping, so the Appendix A + // index/loop limitations are necessary. Workarounds that are needed to + // support dynamic indexing of vectors on HLSL also don't work on D3D9. + limitations->shadersRequireIndexedLoopValidation = true; + + // D3D9 cannot support constant color and alpha blend funcs together + limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; + + // D3D9 cannot support unclamped constant blend color + limitations->noUnclampedBlendColor = true; + + // D3D9 cannot support packing more than one variable to a single varying. + // TODO(jmadill): Implement more sophisticated component packing in D3D9. + limitations->noFlexibleVaryingPacking = true; + + // D3D9 does not support vertex attribute aliasing + limitations->noVertexAttributeAliasing = true; + + // D3D9 does not support compressed textures where the base mip level is not a multiple of 4 + limitations->compressedBaseMipLevelMultipleOfFour = true; +} + +} // namespace d3d9_gl + +namespace d3d9 +{ + +GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + GLuint numBlocksWide = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth; + GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight; + return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight); +} + +void MakeValidSize(bool isImage, + D3DFORMAT format, + GLsizei *requestWidth, + GLsizei *requestHeight, + int *levelOffset) +{ + const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format); + + int upsampleCount = 0; + // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already. + if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) || + *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight)) + { + while (*requestWidth % d3dFormatInfo.blockWidth != 0 || + *requestHeight % d3dFormatInfo.blockHeight != 0) + { + *requestWidth <<= 1; + *requestHeight <<= 1; + upsampleCount++; + } + } + *levelOffset = upsampleCount; +} + +void InitializeFeatures(angle::FeaturesD3D *features) +{ + ANGLE_FEATURE_CONDITION(features, mrtPerfWorkaround, true); + ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUpload, false); + ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUploadOn128bitFormats, false); + ANGLE_FEATURE_CONDITION(features, useInstancedPointSpriteEmulation, false); + + // TODO(jmadill): Disable workaround when we have a fixed compiler DLL. + ANGLE_FEATURE_CONDITION(features, expandIntegerPowExpressions, true); + + // crbug.com/1011627 Turn this on for D3D9. + ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true); +} + +} // namespace d3d9 + +} // namespace rx |