blob: bed71acf8a8255f47ec103f6e41297929e2d2e61 [file] [log] [blame]
//
// Copyright (c) 2002-2014 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/mathutil.h"
#include "common/debug.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
#include "libANGLE/renderer/d3d/d3d9/RenderTarget9.h"
#include "libANGLE/renderer/d3d/FramebufferD3D.h"
#include "libANGLE/renderer/driver_utils.h"
#include "platform/Platform.h"
#include "platform/WorkaroundsD3D.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_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break;
default: UNREACHABLE();
}
return d3dWrap;
}
D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
{
D3DCULL cull = D3DCULL_CCW;
switch (cullFace)
{
case GL_FRONT:
cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
break;
case GL_BACK:
cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
break;
case GL_FRONT_AND_BACK:
cull = D3DCULL_NONE; // culling will be handled during draw
break;
default: UNREACHABLE();
}
return cull;
}
D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
{
D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
switch (cubeFace)
{
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
face = D3DCUBEMAP_FACE_POSITIVE_X;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
face = D3DCUBEMAP_FACE_NEGATIVE_X;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
face = D3DCUBEMAP_FACE_POSITIVE_Y;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
face = D3DCUBEMAP_FACE_NEGATIVE_Y;
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
face = D3DCUBEMAP_FACE_POSITIVE_Z;
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
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(GLenum queryType)
{
switch (queryType)
{
case GL_ANY_SAMPLES_PASSED_EXT:
case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
return D3DQUERYTYPE_OCCLUSION;
case GL_COMMANDS_COMPLETED_CHROMIUM:
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 d3d9_gl
{
unsigned int GetReservedVertexUniformVectors()
{
return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
}
unsigned int GetReservedFragmentUniformVectors()
{
return 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
}
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));
}
textureCaps.filterable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
}
if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)
{
textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) && !textureCaps.renderable)
{
textureCaps.renderable = SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
}
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, &currentDisplayMode);
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());
if (gl::GetSizedInternalFormatInfo(internalFormat).compressed)
{
caps->compressedTextureFormats.push_back(internalFormat);
}
}
// 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->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4;
caps->maxVertexUniformBlocks = 0;
// SM3 only supports 11 output variables, with a special 12th register for PSIZE.
const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9;
const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7;
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->maxVertexTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3;
}
else
{
caps->maxVertexTextureImageUnits = 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->maxFragmentUniformComponents = caps->maxFragmentUniformVectors * 4;
caps->maxFragmentUniformBlocks = 0;
caps->maxFragmentInputComponents = caps->maxVertexOutputComponents;
caps->maxTextureImageUnits = 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->maxCombinedVertexUniformComponents = 0;
caps->maxCombinedFragmentUniformComponents = 0;
caps->maxVaryingComponents = 0;
// Aggregate shader limits
caps->maxVaryingVectors = caps->maxVertexOutputComponents / 4;
caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits;
// Transform feedback limits
caps->maxTransformFeedbackInterleavedComponents = 0;
caps->maxTransformFeedbackSeparateAttributes = 0;
caps->maxTransformFeedbackSeparateComponents = 0;
// Multisample limits
caps->maxSamples = maxSamples;
// GL extension support
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16);
extensions->getProgramBinary = true;
extensions->rgb8rgba8 = true;
extensions->readFormatBGRA = true;
extensions->pixelBufferObject = false;
extensions->mapBuffer = false;
extensions->mapBufferRange = false;
// textureRG is emulated and not performant.
extensions->textureRG = false;
D3DADAPTER_IDENTIFIER9 adapterId = {};
if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
{
// ATI cards on XP have problems with non-power-of-two textures.
extensions->textureNPOT = !(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->depthTextures = false;
}
}
else
{
extensions->textureNPOT = false;
}
extensions->drawBuffers = false;
extensions->textureStorage = true;
// Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per the spec
extensions->textureFilterAnisotropic = (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2;
extensions->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy);
// Check occlusion query support by trying to create one
IDirect3DQuery9 *occlusionQuery = nullptr;
extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery;
SafeRelease(occlusionQuery);
// Check event query support by trying to create one
IDirect3DQuery9 *eventQuery = nullptr;
extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery;
SafeRelease(eventQuery);
extensions->timerQuery = false; // Unimplemented
extensions->disjointTimerQuery = false;
extensions->robustness = true;
extensions->blendMinMax = true;
extensions->framebufferBlit = true;
extensions->framebufferMultisample = true;
extensions->instancedArrays = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
extensions->packReverseRowOrder = true;
extensions->standardDerivatives = (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
extensions->shaderTextureLOD = true;
extensions->fragDepth = true;
extensions->textureUsage = true;
extensions->translatedShaderSource = true;
extensions->fboRenderMipmap = false;
extensions->discardFramebuffer = false; // It would be valid to set this to true, since glDiscardFramebufferEXT is just a hint
extensions->colorBufferFloat = false;
extensions->debugMarker = true;
extensions->eglImage = true;
extensions->eglImageExternal = true;
extensions->unpackSubimage = true;
extensions->packSubimage = true;
extensions->syncQuery = extensions->fence;
extensions->copyTexture = 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;
}
}
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;
}
angle::WorkaroundsD3D GenerateWorkarounds()
{
angle::WorkaroundsD3D workarounds;
workarounds.mrtPerfWorkaround = true;
workarounds.setDataFasterThanImageUpload = false;
workarounds.useInstancedPointSpriteEmulation = false;
// TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
workarounds.expandIntegerPowExpressions = true;
// Call platform hooks for testing overrides.
auto *platform = ANGLEPlatformCurrent();
platform->overrideWorkaroundsD3D(platform, &workarounds);
return workarounds;
}
} // namespace d3d9
} // namespace rx