• 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         }
442 
443         textureCaps.filterable = SUCCEEDED(
444             d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER,
445                                     D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
446     }
447 
448     if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)
449     {
450         textureCaps.textureAttachment = SUCCEEDED(
451             d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET,
452                                     D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
453 
454         if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) &&
455             !textureCaps.textureAttachment)
456         {
457             textureCaps.textureAttachment = SUCCEEDED(
458                 d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL,
459                                         D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
460         }
461         textureCaps.renderbuffer = textureCaps.textureAttachment;
462         textureCaps.blendable    = textureCaps.renderbuffer;
463 
464         textureCaps.sampleCounts.insert(1);
465         for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++)
466         {
467             D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i);
468 
469             HRESULT result = d3d9->CheckDeviceMultiSampleType(
470                 adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr);
471             if (SUCCEEDED(result))
472             {
473                 textureCaps.sampleCounts.insert(i);
474             }
475         }
476     }
477 
478     return textureCaps;
479 }
480 
GenerateCaps(IDirect3D9 * d3d9,IDirect3DDevice9 * device,D3DDEVTYPE deviceType,UINT adapter,gl::Caps * caps,gl::TextureCapsMap * textureCapsMap,gl::Extensions * extensions,gl::Limitations * limitations)481 void GenerateCaps(IDirect3D9 *d3d9,
482                   IDirect3DDevice9 *device,
483                   D3DDEVTYPE deviceType,
484                   UINT adapter,
485                   gl::Caps *caps,
486                   gl::TextureCapsMap *textureCapsMap,
487                   gl::Extensions *extensions,
488                   gl::Limitations *limitations)
489 {
490     D3DCAPS9 deviceCaps;
491     if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps)))
492     {
493         // Can't continue with out device caps
494         return;
495     }
496 
497     D3DDISPLAYMODE currentDisplayMode;
498     d3d9->GetAdapterDisplayMode(adapter, &currentDisplayMode);
499 
500     GLuint maxSamples = 0;
501     for (GLenum internalFormat : gl::GetAllSizedInternalFormats())
502     {
503         gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType,
504                                                                 adapter, currentDisplayMode.Format);
505         textureCapsMap->insert(internalFormat, textureCaps);
506 
507         maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
508 
509         if (gl::GetSizedInternalFormatInfo(internalFormat).compressed)
510         {
511             caps->compressedTextureFormats.push_back(internalFormat);
512         }
513     }
514 
515     // GL core feature limits
516     caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
517 
518     // 3D textures are unimplemented in D3D9
519     caps->max3DTextureSize = 1;
520 
521     // Only one limit in GL, use the minimum dimension
522     caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight);
523 
524     // D3D treats cube maps as a special case of 2D textures
525     caps->maxCubeMapTextureSize = caps->max2DTextureSize;
526 
527     // Array textures are not available in D3D9
528     caps->maxArrayTextureLayers = 1;
529 
530     // ES3-only feature
531     caps->maxLODBias = 0.0f;
532 
533     // No specific limits on render target size, maximum 2D texture size is equivalent
534     caps->maxRenderbufferSize = caps->max2DTextureSize;
535 
536     // Draw buffers are not supported in D3D9
537     caps->maxDrawBuffers      = 1;
538     caps->maxColorAttachments = 1;
539 
540     // No specific limits on viewport size, maximum 2D texture size is equivalent
541     caps->maxViewportWidth  = caps->max2DTextureSize;
542     caps->maxViewportHeight = caps->maxViewportWidth;
543 
544     // Point size is clamped to 1.0f when the shader model is less than 3
545     caps->minAliasedPointSize = 1.0f;
546     caps->maxAliasedPointSize =
547         ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize
548                                                                        : 1.0f);
549 
550     // Wide lines not supported
551     caps->minAliasedLineWidth = 1.0f;
552     caps->maxAliasedLineWidth = 1.0f;
553 
554     // Primitive count limits (unused in ES2)
555     caps->maxElementsIndices  = 0;
556     caps->maxElementsVertices = 0;
557 
558     // Program and shader binary formats (no supported shader binary formats)
559     caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
560 
561     caps->vertexHighpFloat.setIEEEFloat();
562     caps->vertexMediumpFloat.setIEEEFloat();
563     caps->vertexLowpFloat.setIEEEFloat();
564     caps->fragmentHighpFloat.setIEEEFloat();
565     caps->fragmentMediumpFloat.setIEEEFloat();
566     caps->fragmentLowpFloat.setIEEEFloat();
567 
568     // Some (most) hardware only supports single-precision floating-point numbers,
569     // which can accurately represent integers up to +/-16777216
570     caps->vertexHighpInt.setSimulatedInt(24);
571     caps->vertexMediumpInt.setSimulatedInt(24);
572     caps->vertexLowpInt.setSimulatedInt(24);
573     caps->fragmentHighpInt.setSimulatedInt(24);
574     caps->fragmentMediumpInt.setSimulatedInt(24);
575     caps->fragmentLowpInt.setSimulatedInt(24);
576 
577     // WaitSync is ES3-only, set to zero
578     caps->maxServerWaitTimeout = 0;
579 
580     // Vertex shader limits
581     caps->maxVertexAttributes = 16;
582     // Vertex Attrib Binding not supported.
583     caps->maxVertexAttribBindings = caps->maxVertexAttributes;
584 
585     const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
586     caps->maxVertexUniformVectors =
587         MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors();
588     caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4;
589 
590     caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0;
591 
592     // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE.
593     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors();
594     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors();
595     caps->maxVertexOutputComponents =
596         ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
597                                                                  : MAX_VERTEX_OUTPUT_VECTORS_SM2) *
598         4;
599 
600     // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
601     // We test this using D3D9 by checking support for the R16F format.
602     if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) &&
603         SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format,
604                                           D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE,
605                                           D3DFMT_R16F)))
606     {
607         const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3             = 4;
608         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3;
609     }
610     else
611     {
612         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0;
613     }
614 
615     // Fragment shader limits
616     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224;
617     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32;
618     caps->maxFragmentUniformVectors =
619         ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
620                                                                 : MAX_PIXEL_CONSTANT_VECTORS_SM2) -
621         GetReservedFragmentUniformVectors();
622     caps->maxShaderUniformComponents[gl::ShaderType::Fragment] =
623         caps->maxFragmentUniformVectors * 4;
624     caps->maxShaderUniformBlocks[gl::ShaderType::Fragment]     = 0;
625     caps->maxFragmentInputComponents                           = caps->maxVertexOutputComponents;
626     caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 16;
627     caps->minProgramTexelOffset                                = 0;
628     caps->maxProgramTexelOffset                                = 0;
629 
630     // Aggregate shader limits (unused in ES2)
631     caps->maxUniformBufferBindings                                     = 0;
632     caps->maxUniformBlockSize                                          = 0;
633     caps->uniformBufferOffsetAlignment                                 = 0;
634     caps->maxCombinedUniformBlocks                                     = 0;
635     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex]   = 0;
636     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0;
637     caps->maxVaryingComponents                                         = 0;
638 
639     // Aggregate shader limits
640     caps->maxVaryingVectors            = caps->maxVertexOutputComponents / 4;
641     caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] +
642                                          caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment];
643 
644     // Transform feedback limits
645     caps->maxTransformFeedbackInterleavedComponents = 0;
646     caps->maxTransformFeedbackSeparateAttributes    = 0;
647     caps->maxTransformFeedbackSeparateComponents    = 0;
648 
649     // Multisample limits
650     caps->maxSamples = maxSamples;
651 
652     // GL extension support
653     extensions->setTextureExtensionSupport(*textureCapsMap);
654     extensions->elementIndexUintOES = deviceCaps.MaxVertexIndex >= (1 << 16);
655     extensions->getProgramBinaryOES = true;
656     extensions->rgb8rgba8OES        = true;
657     extensions->readFormatBGRA      = true;
658     extensions->pixelBufferObjectNV = false;
659     extensions->mapBufferOES        = false;
660     extensions->mapBufferRange      = false;
661 
662     // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture
663     // allows for that so we can't implement full support with the D3D9 back end.
664     extensions->depthTextureOES = false;
665 
666     // textureRG is emulated and not performant.
667     extensions->textureRG = false;
668 
669     D3DADAPTER_IDENTIFIER9 adapterId = {};
670     if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
671     {
672         // ATI cards on XP have problems with non-power-of-two textures.
673         extensions->textureNPOTOES =
674             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
675             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
676             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
677             !(!isWindowsVistaOrGreater() && IsAMD(adapterId.VendorId));
678 
679         // Disable depth texture support on AMD cards (See ANGLE issue 839)
680         if (IsAMD(adapterId.VendorId))
681         {
682             extensions->depthTextureANGLE = false;
683             extensions->depthTextureOES   = false;
684         }
685     }
686     else
687     {
688         extensions->textureNPOTOES = false;
689     }
690 
691     extensions->drawBuffers    = false;
692     extensions->textureStorage = true;
693 
694     // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per
695     // the spec
696     extensions->textureFilterAnisotropic =
697         (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2;
698     extensions->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy);
699 
700     // Check occlusion query support by trying to create one
701     IDirect3DQuery9 *occlusionQuery = nullptr;
702     extensions->occlusionQueryBoolean =
703         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery;
704     SafeRelease(occlusionQuery);
705 
706     // Check event query support by trying to create one
707     IDirect3DQuery9 *eventQuery = nullptr;
708     extensions->fenceNV =
709         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery;
710     SafeRelease(eventQuery);
711 
712     extensions->disjointTimerQuery = false;
713     extensions->robustness         = true;
714     // It seems that only DirectX 10 and higher enforce the well-defined behavior of always
715     // returning zero values when out-of-bounds reads. See
716     // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt
717     extensions->robustBufferAccessBehavior = false;
718     extensions->blendMinMax                = true;
719     // Although according to
720     // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware
721     // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide
722     // correct blending result in reality. As a result of some regression reports by client app, we
723     // decided to turn floatBlend on for D3D9
724     extensions->floatBlend             = true;
725     extensions->framebufferBlitANGLE   = true;
726     extensions->framebufferMultisample = true;
727     extensions->instancedArraysANGLE   = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
728     // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT
729     // extension
730     extensions->instancedArraysEXT  = false;
731     extensions->packReverseRowOrder = true;
732     extensions->standardDerivativesOES =
733         (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
734     extensions->shaderTextureLOD       = true;
735     extensions->fragDepth              = true;
736     extensions->textureUsage           = true;
737     extensions->translatedShaderSource = true;
738     extensions->fboRenderMipmapOES     = false;
739     extensions->discardFramebuffer     = false;  // It would be valid to set this to true, since
740                                                  // glDiscardFramebufferEXT is just a hint
741     extensions->colorBufferFloat      = false;
742     extensions->debugMarker           = true;
743     extensions->eglImageOES           = true;
744     extensions->eglImageExternalOES   = true;
745     extensions->unpackSubimage        = true;
746     extensions->packSubimage          = true;
747     extensions->syncQuery             = extensions->fenceNV;
748     extensions->copyTexture           = true;
749     extensions->textureBorderClampOES = true;
750     extensions->webglVideoTexture     = true;
751 
752     // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
753     // state.
754     limitations->noSeparateStencilRefsAndMasks = true;
755 
756     // D3D9 shader models have limited support for looping, so the Appendix A
757     // index/loop limitations are necessary. Workarounds that are needed to
758     // support dynamic indexing of vectors on HLSL also don't work on D3D9.
759     limitations->shadersRequireIndexedLoopValidation = true;
760 
761     // D3D9 cannot support constant color and alpha blend funcs together
762     limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
763 
764     // D3D9 cannot support packing more than one variable to a single varying.
765     // TODO(jmadill): Implement more sophisticated component packing in D3D9.
766     limitations->noFlexibleVaryingPacking = true;
767 
768     // D3D9 does not support vertex attribute aliasing
769     limitations->noVertexAttributeAliasing = true;
770 }
771 
772 }  // namespace d3d9_gl
773 
774 namespace d3d9
775 {
776 
ComputeBlockSize(D3DFORMAT format,GLuint width,GLuint height)777 GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height)
778 {
779     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
780     GLuint numBlocksWide  = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth;
781     GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight;
782     return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight);
783 }
784 
MakeValidSize(bool isImage,D3DFORMAT format,GLsizei * requestWidth,GLsizei * requestHeight,int * levelOffset)785 void MakeValidSize(bool isImage,
786                    D3DFORMAT format,
787                    GLsizei *requestWidth,
788                    GLsizei *requestHeight,
789                    int *levelOffset)
790 {
791     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
792 
793     int upsampleCount = 0;
794     // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already.
795     if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) ||
796         *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight))
797     {
798         while (*requestWidth % d3dFormatInfo.blockWidth != 0 ||
799                *requestHeight % d3dFormatInfo.blockHeight != 0)
800         {
801             *requestWidth <<= 1;
802             *requestHeight <<= 1;
803             upsampleCount++;
804         }
805     }
806     *levelOffset = upsampleCount;
807 }
808 
InitializeFeatures(angle::FeaturesD3D * features)809 void InitializeFeatures(angle::FeaturesD3D *features)
810 {
811     ANGLE_FEATURE_CONDITION(features, mrtPerfWorkaround, true);
812     ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUpload, false);
813     ANGLE_FEATURE_CONDITION(features, useInstancedPointSpriteEmulation, false);
814 
815     // TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
816     ANGLE_FEATURE_CONDITION(features, expandIntegerPowExpressions, true);
817 
818     // crbug.com/1011627 Turn this on for D3D9.
819     ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true);
820 
821     // Call platform hooks for testing overrides.
822     auto *platform = ANGLEPlatformCurrent();
823     platform->overrideWorkaroundsD3D(platform, features);
824 }
825 
826 }  // namespace d3d9
827 
828 }  // namespace rx
829