• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.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 
ConvertComparison(GLenum comparison)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 
ConvertColor(gl::ColorF color)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 
ConvertBlendFunc(GLenum blend)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 
ConvertBlendOp(GLenum blendOp)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 
ConvertStencilOp(GLenum stencilOp)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 
ConvertTextureWrap(GLenum wrap)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 
ConvertCullMode(gl::CullFaceMode cullFace,GLenum frontFace)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 
ConvertCubeFace(gl::TextureTarget cubeFace)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 
ConvertColorMask(bool red,bool green,bool blue,bool alpha)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 
ConvertMagFilter(GLenum magFilter,float maxAnisotropy)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 
ConvertMinFilter(GLenum minFilter,D3DTEXTUREFILTERTYPE * d3dMinFilter,D3DTEXTUREFILTERTYPE * d3dMipFilter,float * d3dLodBias,float maxAnisotropy,size_t baseLevel)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 
ConvertQueryType(gl::QueryType type)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 
GetMultisampleType(GLuint samples)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 
GetReservedVaryingVectors()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 
GetReservedVertexUniformVectors()394 unsigned int GetReservedVertexUniformVectors()
395 {
396     return 3;  // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
397 }
398 
GetReservedFragmentUniformVectors()399 unsigned int GetReservedFragmentUniformVectors()
400 {
401     return 3;  // dx_ViewCoords, dx_DepthFront and dx_DepthRange.
402 }
403 
GetSamplesCount(D3DMULTISAMPLE_TYPE type)404 GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type)
405 {
406     return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0;
407 }
408 
IsFormatChannelEquivalent(D3DFORMAT d3dformat,GLenum format)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 
GenerateTextureFormatCaps(GLenum internalFormat,IDirect3D9 * d3d9,D3DDEVTYPE deviceType,UINT adapter,D3DFORMAT adapterFormat)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 
GenerateCaps(IDirect3D9 * d3d9,IDirect3DDevice9 * device,D3DDEVTYPE deviceType,UINT adapter,gl::Caps * caps,gl::TextureCapsMap * textureCapsMap,gl::Extensions * extensions,gl::Limitations * limitations)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         if (gl::GetSizedInternalFormatInfo(internalFormat).compressed)
526         {
527             caps->compressedTextureFormats.push_back(internalFormat);
528         }
529     }
530 
531     // GL core feature limits
532     caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
533 
534     // 3D textures are unimplemented in D3D9
535     caps->max3DTextureSize = 1;
536 
537     // Only one limit in GL, use the minimum dimension
538     caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight);
539 
540     // D3D treats cube maps as a special case of 2D textures
541     caps->maxCubeMapTextureSize = caps->max2DTextureSize;
542 
543     // Array textures are not available in D3D9
544     caps->maxArrayTextureLayers = 1;
545 
546     // ES3-only feature
547     caps->maxLODBias = 0.0f;
548 
549     // No specific limits on render target size, maximum 2D texture size is equivalent
550     caps->maxRenderbufferSize = caps->max2DTextureSize;
551 
552     // Draw buffers are not supported in D3D9
553     caps->maxDrawBuffers      = 1;
554     caps->maxColorAttachments = 1;
555 
556     // No specific limits on viewport size, maximum 2D texture size is equivalent
557     caps->maxViewportWidth  = caps->max2DTextureSize;
558     caps->maxViewportHeight = caps->maxViewportWidth;
559 
560     // Point size is clamped to 1.0f when the shader model is less than 3
561     caps->minAliasedPointSize = 1.0f;
562     caps->maxAliasedPointSize =
563         ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize
564                                                                        : 1.0f);
565 
566     // Wide lines not supported
567     caps->minAliasedLineWidth = 1.0f;
568     caps->maxAliasedLineWidth = 1.0f;
569 
570     // Primitive count limits (unused in ES2)
571     caps->maxElementsIndices  = 0;
572     caps->maxElementsVertices = 0;
573 
574     // Program and shader binary formats (no supported shader binary formats)
575     caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
576 
577     caps->vertexHighpFloat.setIEEEFloat();
578     caps->vertexMediumpFloat.setIEEEFloat();
579     caps->vertexLowpFloat.setIEEEFloat();
580     caps->fragmentHighpFloat.setIEEEFloat();
581     caps->fragmentMediumpFloat.setIEEEFloat();
582     caps->fragmentLowpFloat.setIEEEFloat();
583 
584     // Some (most) hardware only supports single-precision floating-point numbers,
585     // which can accurately represent integers up to +/-16777216
586     caps->vertexHighpInt.setSimulatedInt(24);
587     caps->vertexMediumpInt.setSimulatedInt(24);
588     caps->vertexLowpInt.setSimulatedInt(24);
589     caps->fragmentHighpInt.setSimulatedInt(24);
590     caps->fragmentMediumpInt.setSimulatedInt(24);
591     caps->fragmentLowpInt.setSimulatedInt(24);
592 
593     // WaitSync is ES3-only, set to zero
594     caps->maxServerWaitTimeout = 0;
595 
596     // Vertex shader limits
597     caps->maxVertexAttributes = 16;
598     // Vertex Attrib Binding not supported.
599     caps->maxVertexAttribBindings = caps->maxVertexAttributes;
600 
601     const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
602     caps->maxVertexUniformVectors =
603         MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors();
604     caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4;
605 
606     caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0;
607 
608     // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE.
609     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors();
610     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors();
611     caps->maxVertexOutputComponents =
612         ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
613                                                                  : MAX_VERTEX_OUTPUT_VECTORS_SM2) *
614         4;
615 
616     // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
617     // We test this using D3D9 by checking support for the R16F format.
618     if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) &&
619         SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format,
620                                           D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE,
621                                           D3DFMT_R16F)))
622     {
623         const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3             = 4;
624         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3;
625     }
626     else
627     {
628         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0;
629     }
630 
631     // Fragment shader limits
632     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224;
633     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32;
634     caps->maxFragmentUniformVectors =
635         ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
636                                                                 : MAX_PIXEL_CONSTANT_VECTORS_SM2) -
637         GetReservedFragmentUniformVectors();
638     caps->maxShaderUniformComponents[gl::ShaderType::Fragment] =
639         caps->maxFragmentUniformVectors * 4;
640     caps->maxShaderUniformBlocks[gl::ShaderType::Fragment]     = 0;
641     caps->maxFragmentInputComponents                           = caps->maxVertexOutputComponents;
642     caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 16;
643     caps->minProgramTexelOffset                                = 0;
644     caps->maxProgramTexelOffset                                = 0;
645 
646     // Aggregate shader limits (unused in ES2)
647     caps->maxUniformBufferBindings                                     = 0;
648     caps->maxUniformBlockSize                                          = 0;
649     caps->uniformBufferOffsetAlignment                                 = 0;
650     caps->maxCombinedUniformBlocks                                     = 0;
651     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex]   = 0;
652     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0;
653     caps->maxVaryingComponents                                         = 0;
654 
655     // Aggregate shader limits
656     caps->maxVaryingVectors            = caps->maxVertexOutputComponents / 4;
657     caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] +
658                                          caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment];
659 
660     // Transform feedback limits
661     caps->maxTransformFeedbackInterleavedComponents = 0;
662     caps->maxTransformFeedbackSeparateAttributes    = 0;
663     caps->maxTransformFeedbackSeparateComponents    = 0;
664 
665     // Multisample limits
666     caps->maxSamples = maxSamples;
667 
668     // GL extension support
669     extensions->setTextureExtensionSupport(*textureCapsMap);
670     extensions->elementIndexUintOES = deviceCaps.MaxVertexIndex >= (1 << 16);
671     extensions->getProgramBinaryOES = true;
672     extensions->rgb8Rgba8OES        = true;
673     extensions->readFormatBgraEXT   = true;
674     extensions->pixelBufferObjectNV = false;
675     extensions->mapbufferOES        = false;
676     extensions->mapBufferRangeEXT   = false;
677 
678     // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture
679     // allows for that so we can't implement full support with the D3D9 back end.
680     extensions->depthTextureOES = false;
681 
682     // textureRgEXT is emulated and not performant.
683     extensions->textureRgEXT = false;
684 
685     // GL_KHR_parallel_shader_compile
686     extensions->parallelShaderCompileKHR = true;
687 
688     D3DADAPTER_IDENTIFIER9 adapterId = {};
689     if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
690     {
691         // ATI cards on XP have problems with non-power-of-two textures.
692         extensions->textureNpotOES =
693             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
694             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
695             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
696             !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId));
697 
698         // Disable depth texture support on AMD cards (See ANGLE issue 839)
699         if (IsAMD(adapterId.VendorId))
700         {
701             extensions->depthTextureANGLE = false;
702             extensions->depthTextureOES   = false;
703         }
704     }
705     else
706     {
707         extensions->textureNpotOES = false;
708     }
709 
710     extensions->drawBuffersEXT    = false;
711     extensions->textureStorageEXT = true;
712 
713     // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per
714     // the spec
715     extensions->textureFilterAnisotropicEXT =
716         (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2;
717     caps->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy);
718 
719     // Check occlusion query support by trying to create one
720     IDirect3DQuery9 *occlusionQuery = nullptr;
721     extensions->occlusionQueryBooleanEXT =
722         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery;
723     SafeRelease(occlusionQuery);
724 
725     // Check event query support by trying to create one
726     IDirect3DQuery9 *eventQuery = nullptr;
727     extensions->fenceNV =
728         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery;
729     SafeRelease(eventQuery);
730 
731     extensions->disjointTimerQueryEXT = false;
732     extensions->robustnessEXT         = true;
733     // It seems that only DirectX 10 and higher enforce the well-defined behavior of always
734     // returning zero values when out-of-bounds reads. See
735     // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt
736     extensions->robustBufferAccessBehaviorKHR = false;
737     extensions->blendMinmaxEXT                = true;
738     // Although according to
739     // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware
740     // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide
741     // correct blending result in reality. As a result of some regression reports by client app, we
742     // decided to turn floatBlendEXT on for D3D9
743     extensions->floatBlendEXT               = true;
744     extensions->framebufferBlitANGLE        = true;
745     extensions->framebufferMultisampleANGLE = true;
746     extensions->instancedArraysANGLE        = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
747     // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT
748     // extension
749     extensions->instancedArraysEXT       = false;
750     extensions->packReverseRowOrderANGLE = true;
751     extensions->standardDerivativesOES =
752         (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
753     extensions->shaderTextureLodEXT         = true;
754     extensions->fragDepthEXT                = true;
755     extensions->textureUsageANGLE           = true;
756     extensions->translatedShaderSourceANGLE = true;
757     extensions->fboRenderMipmapOES          = false;
758     extensions->discardFramebufferEXT = false;  // It would be valid to set this to true, since
759                                                 // glDiscardFramebufferEXT is just a hint
760     extensions->colorBufferFloatEXT   = false;
761     extensions->debugMarkerEXT        = true;
762     extensions->EGLImageOES           = true;
763     extensions->EGLImageExternalOES   = true;
764     extensions->unpackSubimageEXT     = true;
765     extensions->packSubimageNV        = true;
766     extensions->syncQueryCHROMIUM     = extensions->fenceNV;
767     extensions->copyTextureCHROMIUM   = true;
768     extensions->textureBorderClampOES = true;
769     extensions->videoTextureWEBGL     = true;
770 
771     // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
772     // state.
773     limitations->noSeparateStencilRefsAndMasks = true;
774 
775     // D3D9 shader models have limited support for looping, so the Appendix A
776     // index/loop limitations are necessary. Workarounds that are needed to
777     // support dynamic indexing of vectors on HLSL also don't work on D3D9.
778     limitations->shadersRequireIndexedLoopValidation = true;
779 
780     // D3D9 cannot support constant color and alpha blend funcs together
781     limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
782 
783     // D3D9 cannot support packing more than one variable to a single varying.
784     // TODO(jmadill): Implement more sophisticated component packing in D3D9.
785     limitations->noFlexibleVaryingPacking = true;
786 
787     // D3D9 does not support vertex attribute aliasing
788     limitations->noVertexAttributeAliasing = true;
789 
790     // D3D9 does not support compressed textures where the base mip level is not a multiple of 4
791     limitations->compressedBaseMipLevelMultipleOfFour = true;
792 }
793 
794 }  // namespace d3d9_gl
795 
796 namespace d3d9
797 {
798 
ComputeBlockSize(D3DFORMAT format,GLuint width,GLuint height)799 GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height)
800 {
801     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
802     GLuint numBlocksWide  = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth;
803     GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight;
804     return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight);
805 }
806 
MakeValidSize(bool isImage,D3DFORMAT format,GLsizei * requestWidth,GLsizei * requestHeight,int * levelOffset)807 void MakeValidSize(bool isImage,
808                    D3DFORMAT format,
809                    GLsizei *requestWidth,
810                    GLsizei *requestHeight,
811                    int *levelOffset)
812 {
813     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
814 
815     int upsampleCount = 0;
816     // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already.
817     if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) ||
818         *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight))
819     {
820         while (*requestWidth % d3dFormatInfo.blockWidth != 0 ||
821                *requestHeight % d3dFormatInfo.blockHeight != 0)
822         {
823             *requestWidth <<= 1;
824             *requestHeight <<= 1;
825             upsampleCount++;
826         }
827     }
828     *levelOffset = upsampleCount;
829 }
830 
InitializeFeatures(angle::FeaturesD3D * features)831 void InitializeFeatures(angle::FeaturesD3D *features)
832 {
833     ANGLE_FEATURE_CONDITION(features, mrtPerfWorkaround, true);
834     ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUpload, false);
835     ANGLE_FEATURE_CONDITION(features, useInstancedPointSpriteEmulation, false);
836 
837     // TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
838     ANGLE_FEATURE_CONDITION(features, expandIntegerPowExpressions, true);
839 
840     // crbug.com/1011627 Turn this on for D3D9.
841     ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true);
842 }
843 
844 }  // namespace d3d9
845 
846 }  // namespace rx
847