void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) { 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; const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) { gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, currentDisplayMode.Format); textureCapsMap->insert(*internalFormat, textureCaps); maxSamples = std::max(maxSamples, textureCaps.getMaxSamples()); if (gl::GetInternalFormatInfo(*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; const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange. const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256; caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors; 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 reservedPixelUniformVectors = 3; // dx_ViewCoords, dx_DepthFront and dx_DepthRange. 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) - reservedPixelUniformVectors; 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() && adapterId.VendorId == VENDOR_ID_AMD); // Disable depth texture support on AMD cards (See ANGLE issue 839) if (adapterId.VendorId == VENDOR_ID_AMD) { 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 = NULL; extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; SafeRelease(occlusionQuery); // Check event query support by trying to create one IDirect3DQuery9 *eventQuery = NULL; extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; SafeRelease(eventQuery); extensions->timerQuery = false; // Unimplemented 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; }
void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions, gl::Version *maxSupportedESVersion) { // Texture format support checks const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); for (GLenum internalFormat : allFormats) { gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat); textureCapsMap->insert(internalFormat, textureCaps); if (gl::GetInternalFormatInfo(internalFormat).compressed) { caps->compressedTextureFormats.push_back(internalFormat); } } // Start by assuming ES3 support and work down *maxSupportedESVersion = gl::Version(3, 0); // Table 6.28, implementation dependent values if (functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_ARB_ES3_compatibility") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxElementIndex = QuerySingleGLInt64(functions, GL_MAX_ELEMENT_INDEX); } else { // Doesn't affect ES3 support, can use a pre-defined limit caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max()); } if (functions->isAtLeastGL(gl::Version(1, 2)) || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_texture_3D")) { caps->max3DTextureSize = QuerySingleGLInt(functions, GL_MAX_3D_TEXTURE_SIZE); } else { // Can't support ES3 without 3D textures LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } caps->max2DTextureSize = QuerySingleGLInt(functions, GL_MAX_TEXTURE_SIZE); // GL 1.0 / ES 2.0 caps->maxCubeMapTextureSize = QuerySingleGLInt(functions, GL_MAX_CUBE_MAP_TEXTURE_SIZE); // GL 1.3 / ES 2.0 if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_texture_array") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxArrayTextureLayers = QuerySingleGLInt(functions, GL_MAX_ARRAY_TEXTURE_LAYERS); } else { // Can't support ES3 without array textures LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_EXT_texture_lod_bias") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxLODBias = QuerySingleGLFloat(functions, GL_MAX_TEXTURE_LOD_BIAS); } else { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxRenderbufferSize = QuerySingleGLInt(functions, GL_MAX_RENDERBUFFER_SIZE); caps->maxColorAttachments = QuerySingleGLInt(functions, GL_MAX_COLOR_ATTACHMENTS); } else { // Can't support ES2 without framebuffers and renderbuffers LimitVersion(maxSupportedESVersion, gl::Version(0, 0)); } if (functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("ARB_draw_buffers") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers")) { caps->maxDrawBuffers = QuerySingleGLInt(functions, GL_MAX_DRAW_BUFFERS); } else { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } caps->maxViewportWidth = QueryGLIntRange(functions, GL_MAX_VIEWPORT_DIMS, 0); // GL 1.0 / ES 2.0 caps->maxViewportHeight = QueryGLIntRange(functions, GL_MAX_VIEWPORT_DIMS, 1); // GL 1.0 / ES 2.0 if (functions->standard == STANDARD_GL_DESKTOP && (functions->profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0) { // Desktop GL core profile deprecated the GL_ALIASED_POINT_SIZE_RANGE query. Use // GL_POINT_SIZE_RANGE instead. caps->minAliasedPointSize = QueryGLFloatRange(functions, GL_POINT_SIZE_RANGE, 0); caps->maxAliasedPointSize = QueryGLFloatRange(functions, GL_POINT_SIZE_RANGE, 1); } else { caps->minAliasedPointSize = QueryGLFloatRange(functions, GL_ALIASED_POINT_SIZE_RANGE, 0); caps->maxAliasedPointSize = QueryGLFloatRange(functions, GL_ALIASED_POINT_SIZE_RANGE, 1); } caps->minAliasedLineWidth = QueryGLFloatRange(functions, GL_ALIASED_LINE_WIDTH_RANGE, 0); // GL 1.2 / ES 2.0 caps->maxAliasedLineWidth = QueryGLFloatRange(functions, GL_ALIASED_LINE_WIDTH_RANGE, 1); // GL 1.2 / ES 2.0 // Table 6.29, implementation dependent values (cont.) if (functions->isAtLeastGL(gl::Version(1, 2)) || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxElementsIndices = QuerySingleGLInt(functions, GL_MAX_ELEMENTS_INDICES); caps->maxElementsVertices = QuerySingleGLInt(functions, GL_MAX_ELEMENTS_VERTICES); } else { // Doesn't impact supported version } // glGetShaderPrecisionFormat is not available until desktop GL version 4.1 or GL_ARB_ES2_compatibility exists if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->vertexHighpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_HIGH_FLOAT); caps->vertexMediumpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_MEDIUM_FLOAT); caps->vertexLowpFloat = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_LOW_FLOAT); caps->fragmentHighpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_HIGH_FLOAT); caps->fragmentMediumpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT); caps->fragmentLowpFloat = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_LOW_FLOAT); caps->vertexHighpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_HIGH_INT); caps->vertexMediumpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_MEDIUM_INT); caps->vertexLowpInt = QueryTypePrecision(functions, GL_VERTEX_SHADER, GL_LOW_INT); caps->fragmentHighpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_HIGH_INT); caps->fragmentMediumpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_MEDIUM_INT); caps->fragmentLowpInt = QueryTypePrecision(functions, GL_FRAGMENT_SHADER, GL_LOW_INT); } else { // Doesn't impact supported version, set some default values caps->vertexHighpFloat.setIEEEFloat(); caps->vertexMediumpFloat.setIEEEFloat(); caps->vertexLowpFloat.setIEEEFloat(); caps->fragmentHighpFloat.setIEEEFloat(); caps->fragmentMediumpFloat.setIEEEFloat(); caps->fragmentLowpFloat.setIEEEFloat(); caps->vertexHighpInt.setTwosComplementInt(32); caps->vertexMediumpInt.setTwosComplementInt(32); caps->vertexLowpInt.setTwosComplementInt(32); caps->fragmentHighpInt.setTwosComplementInt(32); caps->fragmentMediumpInt.setTwosComplementInt(32); caps->fragmentLowpInt.setTwosComplementInt(32); } if (functions->isAtLeastGL(gl::Version(3, 2)) || functions->hasGLExtension("GL_ARB_sync") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxServerWaitTimeout = QuerySingleGLInt64(functions, GL_MAX_SERVER_WAIT_TIMEOUT); } else { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Table 6.31, implementation dependent vertex shader limits if (functions->isAtLeastGL(gl::Version(2, 0)) || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxVertexAttributes = QuerySingleGLInt(functions, GL_MAX_VERTEX_ATTRIBS); caps->maxVertexUniformComponents = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_COMPONENTS); caps->maxVertexTextureImageUnits = QuerySingleGLInt(functions, GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); } else { // Can't support ES2 version without these caps LimitVersion(maxSupportedESVersion, gl::Version(0, 0)); } if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxVertexUniformVectors = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_VECTORS); } else { // Doesn't limit ES version, GL_MAX_VERTEX_UNIFORM_COMPONENTS / 4 is acceptable. caps->maxVertexUniformVectors = caps->maxVertexUniformComponents / 4; } if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxVertexUniformBlocks = QuerySingleGLInt(functions, GL_MAX_VERTEX_UNIFORM_BLOCKS); } else { // Can't support ES3 without uniform blocks LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(3, 2)) || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxVertexOutputComponents = QuerySingleGLInt(functions, GL_MAX_VERTEX_OUTPUT_COMPONENTS); } else { // There doesn't seem, to be a desktop extension to add this cap, maybe it could be given a safe limit // instead of limiting the supported ES version. LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Table 6.32, implementation dependent fragment shader limits if (functions->isAtLeastGL(gl::Version(2, 0)) || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxFragmentUniformComponents = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS); caps->maxTextureImageUnits = QuerySingleGLInt(functions, GL_MAX_TEXTURE_IMAGE_UNITS); } else { // Can't support ES2 version without these caps LimitVersion(maxSupportedESVersion, gl::Version(0, 0)); } if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxFragmentUniformVectors = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_VECTORS); } else { // Doesn't limit ES version, GL_MAX_FRAGMENT_UNIFORM_COMPONENTS / 4 is acceptable. caps->maxFragmentUniformVectors = caps->maxFragmentUniformComponents / 4; } if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxFragmentUniformBlocks = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_UNIFORM_BLOCKS); } else { // Can't support ES3 without uniform blocks LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(3, 2)) || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxFragmentInputComponents = QuerySingleGLInt(functions, GL_MAX_FRAGMENT_INPUT_COMPONENTS); } else { // There doesn't seem, to be a desktop extension to add this cap, maybe it could be given a safe limit // instead of limiting the supported ES version. LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->minProgramTexelOffset = QuerySingleGLInt(functions, GL_MIN_PROGRAM_TEXEL_OFFSET); caps->maxProgramTexelOffset = QuerySingleGLInt(functions, GL_MAX_PROGRAM_TEXEL_OFFSET); } else { // Can't support ES3 without texel offset, could possibly be emulated in the shader LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Table 6.33, implementation dependent aggregate shader limits if (functions->isAtLeastGL(gl::Version(3, 1)) || functions->hasGLExtension("GL_ARB_uniform_buffer_object") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxUniformBufferBindings = QuerySingleGLInt(functions, GL_MAX_UNIFORM_BUFFER_BINDINGS); caps->maxUniformBlockSize = QuerySingleGLInt64(functions, GL_MAX_UNIFORM_BLOCK_SIZE); caps->uniformBufferOffsetAlignment = QuerySingleGLInt(functions, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); caps->maxCombinedUniformBlocks = caps->maxVertexUniformBlocks + caps->maxFragmentInputComponents; caps->maxCombinedVertexUniformComponents = QuerySingleGLInt64(functions, GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS); caps->maxCombinedFragmentUniformComponents = QuerySingleGLInt64(functions, GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS); } else { // Can't support ES3 without uniform blocks LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_ES3_compatibility") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxVaryingComponents = QuerySingleGLInt(functions, GL_MAX_VARYING_COMPONENTS); } else if (functions->isAtLeastGL(gl::Version(2, 0))) { caps->maxVaryingComponents = QuerySingleGLInt(functions, GL_MAX_VARYING_FLOATS); LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } else { LimitVersion(maxSupportedESVersion, gl::Version(0, 0)); } if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") || functions->isAtLeastGLES(gl::Version(2, 0))) { caps->maxVaryingVectors = QuerySingleGLInt(functions, GL_MAX_VARYING_VECTORS); } else { // Doesn't limit ES version, GL_MAX_VARYING_COMPONENTS / 4 is acceptable. caps->maxVaryingVectors = caps->maxVaryingComponents / 4; } // Determine the max combined texture image units by adding the vertex and fragment limits. If // the real cap is queried, it would contain the limits for shader types that are not available to ES. caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits; // Table 6.34, implementation dependent transform feedback limits if (functions->isAtLeastGL(gl::Version(4, 0)) || functions->hasGLExtension("GL_ARB_transform_feedback2") || functions->isAtLeastGLES(gl::Version(3, 0))) { caps->maxTransformFeedbackInterleavedComponents = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS); caps->maxTransformFeedbackSeparateAttributes = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS); caps->maxTransformFeedbackSeparateComponents = QuerySingleGLInt(functions, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS); } else { // Can't support ES3 without transform feedback LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Table 6.35, Framebuffer Dependent Values if (functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_multisample") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_multisampled_render_to_texture")) { caps->maxSamples = QuerySingleGLInt(functions, GL_MAX_SAMPLES); } else { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Check if sampler objects are supported if (!functions->isAtLeastGL(gl::Version(3, 3)) && !functions->hasGLExtension("GL_ARB_sampler_objects") && !functions->isAtLeastGLES(gl::Version(3, 0))) { // Can't support ES3 without sampler objects LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // Can't support ES3 without texture swizzling if (!functions->isAtLeastGL(gl::Version(3, 3)) && !functions->hasGLExtension("GL_ARB_texture_swizzle") && !functions->hasGLExtension("GL_EXT_texture_swizzle") && !functions->isAtLeastGLES(gl::Version(3, 0))) { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); // Texture swizzling is required to work around the luminance texture format not being // present in the core profile if (functions->profile & GL_CONTEXT_CORE_PROFILE_BIT) { LimitVersion(maxSupportedESVersion, gl::Version(0, 0)); } } // Can't support ES3 without the GLSL packing builtins. We have a workaround for all // desktop OpenGL versions starting from 3.3 with the bit packing extension. if (!functions->isAtLeastGL(gl::Version(4, 2)) && !(functions->isAtLeastGL(gl::Version(3, 2)) && functions->hasGLExtension("GL_ARB_shader_bit_encoding")) && !functions->hasGLExtension("GL_ARB_shading_language_packing") && !functions->isAtLeastGLES(gl::Version(3, 0))) { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // ES3 needs to support explicit layout location qualifiers, while it might be possible to // fake them in our side, we currently don't support that. if (!functions->isAtLeastGL(gl::Version(3, 3)) && !functions->hasGLExtension("GL_ARB_explicit_attrib_location") && !functions->isAtLeastGLES(gl::Version(3, 0))) { LimitVersion(maxSupportedESVersion, gl::Version(2, 0)); } // TODO(geofflang): The gl-uniform-arrays WebGL conformance test struggles to complete on time // if the max uniform vectors is too large. Artificially limit the maximum until the test is // updated. caps->maxVertexUniformVectors = std::min(1024u, caps->maxVertexUniformVectors); caps->maxVertexUniformComponents = std::min(caps->maxVertexUniformVectors / 4, caps->maxVertexUniformComponents); caps->maxFragmentUniformVectors = std::min(1024u, caps->maxFragmentUniformVectors); caps->maxFragmentUniformComponents = std::min(caps->maxFragmentUniformVectors / 4, caps->maxFragmentUniformComponents); // Extension support extensions->setTextureExtensionSupport(*textureCapsMap); extensions->elementIndexUint = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_element_index_uint"); extensions->readFormatBGRA = functions->isAtLeastGL(gl::Version(1, 2)) || functions->hasGLExtension("GL_EXT_bgra") || functions->hasGLESExtension("GL_EXT_read_format_bgra"); extensions->mapBuffer = functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLESExtension("GL_OES_mapbuffer"); extensions->mapBufferRange = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_map_buffer_range") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_map_buffer_range"); extensions->textureNPOT = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_texture_npot"); extensions->drawBuffers = functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("ARB_draw_buffers") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_draw_buffers"); extensions->textureStorage = true; extensions->textureFilterAnisotropic = functions->hasGLExtension("GL_EXT_texture_filter_anisotropic") || functions->hasGLESExtension("GL_EXT_texture_filter_anisotropic"); extensions->occlusionQueryBoolean = functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_ARB_occlusion_query2") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_occlusion_query_boolean"); extensions->maxTextureAnisotropy = extensions->textureFilterAnisotropic ? QuerySingleGLFloat(functions, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 0.0f; extensions->fence = functions->hasGLExtension("GL_NV_fence") || functions->hasGLESExtension("GL_NV_fence"); extensions->blendMinMax = functions->isAtLeastGL(gl::Version(1, 5)) || functions->hasGLExtension("GL_EXT_blend_minmax") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_blend_minmax"); extensions->framebufferBlit = (functions->blitFramebuffer != nullptr); extensions->framebufferMultisample = caps->maxSamples > 0; extensions->standardDerivatives = functions->isAtLeastGL(gl::Version(2, 0)) || functions->hasGLExtension("GL_ARB_fragment_shader") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_standard_derivatives"); extensions->shaderTextureLOD = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_shader_texture_lod") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_shader_texture_lod"); extensions->fragDepth = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_frag_depth"); extensions->fboRenderMipmap = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_EXT_framebuffer_object") || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_fbo_render_mipmap"); extensions->instancedArrays = functions->isAtLeastGL(gl::Version(3, 1)) || (functions->hasGLExtension("GL_ARB_instanced_arrays") && (functions->hasGLExtension("GL_ARB_draw_instanced") || functions->hasGLExtension("GL_EXT_draw_instanced"))) || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_instanced_arrays"); extensions->unpackSubimage = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_unpack_subimage"); extensions->packSubimage = functions->standard == STANDARD_GL_DESKTOP || functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_NV_pack_subimage"); extensions->debugMarker = functions->isAtLeastGL(gl::Version(4, 3)) || functions->hasGLExtension("GL_KHR_debug") || functions->isAtLeastGLES(gl::Version(3, 2)) || functions->hasGLESExtension("GL_KHR_debug"); // ANGLE emulates vertex array objects in its GL layer extensions->vertexArrayObject = true; extensions->noError = true; }
void GenerateCaps(IDirect3D9 *d3d9, IDirect3DDevice9 *device, D3DDEVTYPE deviceType, UINT adapter, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap, gl::Extensions *extensions) { D3DCAPS9 deviceCaps; if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps))) { // Can't continue with out device caps return; } D3DDISPLAYMODE currentDisplayMode; d3d9->GetAdapterDisplayMode(adapter, ¤tDisplayMode); const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats(); for (gl::FormatSet::const_iterator internalFormat = allFormats.begin(); internalFormat != allFormats.end(); ++internalFormat) { gl::TextureCaps textureCaps = GenerateTextureFormatCaps(*internalFormat, d3d9, deviceType, adapter, currentDisplayMode.Format); textureCapsMap->insert(*internalFormat, textureCaps); } // 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; // GL extension support extensions->setTextureExtensionSupport(*textureCapsMap); extensions->elementIndexUint = deviceCaps.MaxVertexIndex >= (1 << 16); extensions->packedDepthStencil = true; extensions->getProgramBinary = true; extensions->rgb8rgba8 = true; extensions->readFormatBGRA = true; extensions->pixelBufferObject = false; extensions->mapBuffer = false; extensions->mapBufferRange = false; // ATI cards on XP have problems with non-power-of-two textures. D3DADAPTER_IDENTIFIER9 adapterId = { 0 }; if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId))) { extensions->textureNPOT = !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) && !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) && !(isWindowsVistaOrGreater() && adapterId.VendorId == VENDOR_ID_AMD); } 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 = NULL; extensions->occlusionQueryBoolean = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery; SafeRelease(occlusionQuery); // Check event query support by trying to create one IDirect3DQuery9 *eventQuery = NULL; extensions->fence = SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery; SafeRelease(eventQuery); extensions->timerQuery = false; // Unimplemented 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->colorBufferFloat = false; }
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()); 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->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->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->disjointTimerQuery = false; extensions->robustness = 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->robustBufferAccessBehavior = false; 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; extensions->textureBorderClamp = 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 packing more than one variable to a single varying. // TODO(jmadill): Implement more sophisticated component packing in D3D9. limitations->noFlexibleVaryingPacking = true; }