• 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/PlatformMethods.h"
20 #include "platform/autogen/FeaturesD3D_autogen.h"
21 
22 namespace rx
23 {
24 
25 namespace gl_d3d9
26 {
27 
ConvertComparison(GLenum comparison)28 D3DCMPFUNC ConvertComparison(GLenum comparison)
29 {
30     D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
31     switch (comparison)
32     {
33         case GL_NEVER:
34             d3dComp = D3DCMP_NEVER;
35             break;
36         case GL_ALWAYS:
37             d3dComp = D3DCMP_ALWAYS;
38             break;
39         case GL_LESS:
40             d3dComp = D3DCMP_LESS;
41             break;
42         case GL_LEQUAL:
43             d3dComp = D3DCMP_LESSEQUAL;
44             break;
45         case GL_EQUAL:
46             d3dComp = D3DCMP_EQUAL;
47             break;
48         case GL_GREATER:
49             d3dComp = D3DCMP_GREATER;
50             break;
51         case GL_GEQUAL:
52             d3dComp = D3DCMP_GREATEREQUAL;
53             break;
54         case GL_NOTEQUAL:
55             d3dComp = D3DCMP_NOTEQUAL;
56             break;
57         default:
58             UNREACHABLE();
59     }
60 
61     return d3dComp;
62 }
63 
ConvertColor(gl::ColorF color)64 D3DCOLOR ConvertColor(gl::ColorF color)
65 {
66     return D3DCOLOR_RGBA(gl::unorm<8>(color.red), gl::unorm<8>(color.green),
67                          gl::unorm<8>(color.blue), gl::unorm<8>(color.alpha));
68 }
69 
ConvertBlendFunc(GLenum blend)70 D3DBLEND ConvertBlendFunc(GLenum blend)
71 {
72     D3DBLEND d3dBlend = D3DBLEND_ZERO;
73 
74     switch (blend)
75     {
76         case GL_ZERO:
77             d3dBlend = D3DBLEND_ZERO;
78             break;
79         case GL_ONE:
80             d3dBlend = D3DBLEND_ONE;
81             break;
82         case GL_SRC_COLOR:
83             d3dBlend = D3DBLEND_SRCCOLOR;
84             break;
85         case GL_ONE_MINUS_SRC_COLOR:
86             d3dBlend = D3DBLEND_INVSRCCOLOR;
87             break;
88         case GL_DST_COLOR:
89             d3dBlend = D3DBLEND_DESTCOLOR;
90             break;
91         case GL_ONE_MINUS_DST_COLOR:
92             d3dBlend = D3DBLEND_INVDESTCOLOR;
93             break;
94         case GL_SRC_ALPHA:
95             d3dBlend = D3DBLEND_SRCALPHA;
96             break;
97         case GL_ONE_MINUS_SRC_ALPHA:
98             d3dBlend = D3DBLEND_INVSRCALPHA;
99             break;
100         case GL_DST_ALPHA:
101             d3dBlend = D3DBLEND_DESTALPHA;
102             break;
103         case GL_ONE_MINUS_DST_ALPHA:
104             d3dBlend = D3DBLEND_INVDESTALPHA;
105             break;
106         case GL_CONSTANT_COLOR:
107             d3dBlend = D3DBLEND_BLENDFACTOR;
108             break;
109         case GL_ONE_MINUS_CONSTANT_COLOR:
110             d3dBlend = D3DBLEND_INVBLENDFACTOR;
111             break;
112         case GL_CONSTANT_ALPHA:
113             d3dBlend = D3DBLEND_BLENDFACTOR;
114             break;
115         case GL_ONE_MINUS_CONSTANT_ALPHA:
116             d3dBlend = D3DBLEND_INVBLENDFACTOR;
117             break;
118         case GL_SRC_ALPHA_SATURATE:
119             d3dBlend = D3DBLEND_SRCALPHASAT;
120             break;
121         default:
122             UNREACHABLE();
123     }
124 
125     return d3dBlend;
126 }
127 
ConvertBlendOp(GLenum blendOp)128 D3DBLENDOP ConvertBlendOp(GLenum blendOp)
129 {
130     D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
131 
132     switch (blendOp)
133     {
134         case GL_FUNC_ADD:
135             d3dBlendOp = D3DBLENDOP_ADD;
136             break;
137         case GL_FUNC_SUBTRACT:
138             d3dBlendOp = D3DBLENDOP_SUBTRACT;
139             break;
140         case GL_FUNC_REVERSE_SUBTRACT:
141             d3dBlendOp = D3DBLENDOP_REVSUBTRACT;
142             break;
143         case GL_MIN_EXT:
144             d3dBlendOp = D3DBLENDOP_MIN;
145             break;
146         case GL_MAX_EXT:
147             d3dBlendOp = D3DBLENDOP_MAX;
148             break;
149         default:
150             UNREACHABLE();
151     }
152 
153     return d3dBlendOp;
154 }
155 
ConvertStencilOp(GLenum stencilOp)156 D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
157 {
158     D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
159 
160     switch (stencilOp)
161     {
162         case GL_ZERO:
163             d3dStencilOp = D3DSTENCILOP_ZERO;
164             break;
165         case GL_KEEP:
166             d3dStencilOp = D3DSTENCILOP_KEEP;
167             break;
168         case GL_REPLACE:
169             d3dStencilOp = D3DSTENCILOP_REPLACE;
170             break;
171         case GL_INCR:
172             d3dStencilOp = D3DSTENCILOP_INCRSAT;
173             break;
174         case GL_DECR:
175             d3dStencilOp = D3DSTENCILOP_DECRSAT;
176             break;
177         case GL_INVERT:
178             d3dStencilOp = D3DSTENCILOP_INVERT;
179             break;
180         case GL_INCR_WRAP:
181             d3dStencilOp = D3DSTENCILOP_INCR;
182             break;
183         case GL_DECR_WRAP:
184             d3dStencilOp = D3DSTENCILOP_DECR;
185             break;
186         default:
187             UNREACHABLE();
188     }
189 
190     return d3dStencilOp;
191 }
192 
ConvertTextureWrap(GLenum wrap)193 D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
194 {
195     D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
196 
197     switch (wrap)
198     {
199         case GL_REPEAT:
200             d3dWrap = D3DTADDRESS_WRAP;
201             break;
202         case GL_MIRRORED_REPEAT:
203             d3dWrap = D3DTADDRESS_MIRROR;
204             break;
205         case GL_CLAMP_TO_EDGE:
206             d3dWrap = D3DTADDRESS_CLAMP;
207             break;
208         case GL_CLAMP_TO_BORDER:
209             d3dWrap = D3DTADDRESS_BORDER;
210             break;
211         case GL_MIRROR_CLAMP_TO_EDGE_EXT:
212             d3dWrap = D3DTADDRESS_MIRRORONCE;
213             break;
214         default:
215             UNREACHABLE();
216     }
217 
218     return d3dWrap;
219 }
220 
ConvertCullMode(gl::CullFaceMode cullFace,GLenum frontFace)221 D3DCULL ConvertCullMode(gl::CullFaceMode cullFace, GLenum frontFace)
222 {
223     D3DCULL cull = D3DCULL_CCW;
224     switch (cullFace)
225     {
226         case gl::CullFaceMode::Front:
227             cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
228             break;
229         case gl::CullFaceMode::Back:
230             cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
231             break;
232         case gl::CullFaceMode::FrontAndBack:
233             cull = D3DCULL_NONE;  // culling will be handled during draw
234             break;
235         default:
236             UNREACHABLE();
237     }
238 
239     return cull;
240 }
241 
ConvertCubeFace(gl::TextureTarget cubeFace)242 D3DCUBEMAP_FACES ConvertCubeFace(gl::TextureTarget cubeFace)
243 {
244     D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
245 
246     switch (cubeFace)
247     {
248         case gl::TextureTarget::CubeMapPositiveX:
249             face = D3DCUBEMAP_FACE_POSITIVE_X;
250             break;
251         case gl::TextureTarget::CubeMapNegativeX:
252             face = D3DCUBEMAP_FACE_NEGATIVE_X;
253             break;
254         case gl::TextureTarget::CubeMapPositiveY:
255             face = D3DCUBEMAP_FACE_POSITIVE_Y;
256             break;
257         case gl::TextureTarget::CubeMapNegativeY:
258             face = D3DCUBEMAP_FACE_NEGATIVE_Y;
259             break;
260         case gl::TextureTarget::CubeMapPositiveZ:
261             face = D3DCUBEMAP_FACE_POSITIVE_Z;
262             break;
263         case gl::TextureTarget::CubeMapNegativeZ:
264             face = D3DCUBEMAP_FACE_NEGATIVE_Z;
265             break;
266         default:
267             UNREACHABLE();
268     }
269 
270     return face;
271 }
272 
ConvertColorMask(bool red,bool green,bool blue,bool alpha)273 DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
274 {
275     return (red ? D3DCOLORWRITEENABLE_RED : 0) | (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
276            (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
277 }
278 
ConvertMagFilter(GLenum magFilter,float maxAnisotropy)279 D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
280 {
281     if (maxAnisotropy > 1.0f)
282     {
283         return D3DTEXF_ANISOTROPIC;
284     }
285 
286     D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
287     switch (magFilter)
288     {
289         case GL_NEAREST:
290             d3dMagFilter = D3DTEXF_POINT;
291             break;
292         case GL_LINEAR:
293             d3dMagFilter = D3DTEXF_LINEAR;
294             break;
295         default:
296             UNREACHABLE();
297     }
298 
299     return d3dMagFilter;
300 }
301 
ConvertMinFilter(GLenum minFilter,D3DTEXTUREFILTERTYPE * d3dMinFilter,D3DTEXTUREFILTERTYPE * d3dMipFilter,float * d3dLodBias,float maxAnisotropy,size_t baseLevel)302 void ConvertMinFilter(GLenum minFilter,
303                       D3DTEXTUREFILTERTYPE *d3dMinFilter,
304                       D3DTEXTUREFILTERTYPE *d3dMipFilter,
305                       float *d3dLodBias,
306                       float maxAnisotropy,
307                       size_t baseLevel)
308 {
309     switch (minFilter)
310     {
311         case GL_NEAREST:
312             *d3dMinFilter = D3DTEXF_POINT;
313             *d3dMipFilter = D3DTEXF_NONE;
314             break;
315         case GL_LINEAR:
316             *d3dMinFilter = D3DTEXF_LINEAR;
317             *d3dMipFilter = D3DTEXF_NONE;
318             break;
319         case GL_NEAREST_MIPMAP_NEAREST:
320             *d3dMinFilter = D3DTEXF_POINT;
321             *d3dMipFilter = D3DTEXF_POINT;
322             break;
323         case GL_LINEAR_MIPMAP_NEAREST:
324             *d3dMinFilter = D3DTEXF_LINEAR;
325             *d3dMipFilter = D3DTEXF_POINT;
326             break;
327         case GL_NEAREST_MIPMAP_LINEAR:
328             *d3dMinFilter = D3DTEXF_POINT;
329             *d3dMipFilter = D3DTEXF_LINEAR;
330             break;
331         case GL_LINEAR_MIPMAP_LINEAR:
332             *d3dMinFilter = D3DTEXF_LINEAR;
333             *d3dMipFilter = D3DTEXF_LINEAR;
334             break;
335         default:
336             *d3dMinFilter = D3DTEXF_POINT;
337             *d3dMipFilter = D3DTEXF_NONE;
338             UNREACHABLE();
339     }
340 
341     // Disabling mipmapping will always sample from level 0 of the texture. It is possible to work
342     // around this by modifying D3DSAMP_MAXMIPLEVEL to force a specific mip level to become the
343     // lowest sampled mip level and using a large negative value for D3DSAMP_MIPMAPLODBIAS to
344     // ensure that only the base mip level is sampled.
345     if (baseLevel > 0 && *d3dMipFilter == D3DTEXF_NONE)
346     {
347         *d3dMipFilter = D3DTEXF_POINT;
348         *d3dLodBias   = -static_cast<float>(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
349     }
350     else
351     {
352         *d3dLodBias = 0.0f;
353     }
354 
355     if (maxAnisotropy > 1.0f)
356     {
357         *d3dMinFilter = D3DTEXF_ANISOTROPIC;
358     }
359 }
360 
ConvertQueryType(gl::QueryType type)361 D3DQUERYTYPE ConvertQueryType(gl::QueryType type)
362 {
363     switch (type)
364     {
365         case gl::QueryType::AnySamples:
366         case gl::QueryType::AnySamplesConservative:
367             return D3DQUERYTYPE_OCCLUSION;
368         case gl::QueryType::CommandsCompleted:
369             return D3DQUERYTYPE_EVENT;
370         default:
371             UNREACHABLE();
372             return static_cast<D3DQUERYTYPE>(0);
373     }
374 }
375 
GetMultisampleType(GLuint samples)376 D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples)
377 {
378     return (samples > 1) ? static_cast<D3DMULTISAMPLE_TYPE>(samples) : D3DMULTISAMPLE_NONE;
379 }
380 
381 }  // namespace gl_d3d9
382 
383 namespace d3d9_gl
384 {
385 
GetReservedVaryingVectors()386 unsigned int GetReservedVaryingVectors()
387 {
388     // We reserve two registers for "dx_Position" and "gl_Position". The spec says they
389     // don't count towards the varying limit, so we must make space for them. We also
390     // reserve the last register since it can only pass a PSIZE, and not any arbitrary
391     // varying.
392     return 3;
393 }
394 
GetReservedVertexUniformVectors()395 unsigned int GetReservedVertexUniformVectors()
396 {
397     return 3;  // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
398 }
399 
GetReservedFragmentUniformVectors()400 unsigned int GetReservedFragmentUniformVectors()
401 {
402     return 4;  // dx_ViewCoords, dx_DepthFront, dx_DepthRange, dx_FragCoordoffset.
403 }
404 
GetSamplesCount(D3DMULTISAMPLE_TYPE type)405 GLsizei GetSamplesCount(D3DMULTISAMPLE_TYPE type)
406 {
407     return (type != D3DMULTISAMPLE_NONMASKABLE) ? type : 0;
408 }
409 
IsFormatChannelEquivalent(D3DFORMAT d3dformat,GLenum format)410 bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format)
411 {
412     GLenum internalFormat  = d3d9::GetD3DFormatInfo(d3dformat).info().glInternalFormat;
413     GLenum convertedFormat = gl::GetSizedInternalFormatInfo(internalFormat).format;
414     return convertedFormat == format;
415 }
416 
GenerateTextureFormatCaps(GLenum internalFormat,IDirect3D9 * d3d9,D3DDEVTYPE deviceType,UINT adapter,D3DFORMAT adapterFormat)417 static gl::TextureCaps GenerateTextureFormatCaps(GLenum internalFormat,
418                                                  IDirect3D9 *d3d9,
419                                                  D3DDEVTYPE deviceType,
420                                                  UINT adapter,
421                                                  D3DFORMAT adapterFormat)
422 {
423     gl::TextureCaps textureCaps;
424 
425     const d3d9::TextureFormat &d3dFormatInfo = d3d9::GetTextureFormatInfo(internalFormat);
426     const gl::InternalFormat &formatInfo     = gl::GetSizedInternalFormatInfo(internalFormat);
427 
428     if (d3dFormatInfo.texFormat != D3DFMT_UNKNOWN)
429     {
430         if (formatInfo.depthBits > 0 || formatInfo.stencilBits > 0)
431         {
432             textureCaps.texturable = SUCCEEDED(d3d9->CheckDeviceFormat(
433                 adapter, deviceType, adapterFormat, 0, D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
434         }
435         else
436         {
437             textureCaps.texturable =
438                 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0,
439                                                   D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat)) &&
440                 SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, 0,
441                                                   D3DRTYPE_CUBETEXTURE, d3dFormatInfo.texFormat));
442             if (textureCaps.texturable && (formatInfo.colorEncoding == GL_SRGB))
443             {
444                 textureCaps.texturable =
445                     SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat,
446                                                       D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_TEXTURE,
447                                                       d3dFormatInfo.texFormat)) &&
448                     SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat,
449                                                       D3DUSAGE_QUERY_SRGBREAD, D3DRTYPE_CUBETEXTURE,
450                                                       d3dFormatInfo.texFormat));
451             }
452         }
453 
454         textureCaps.filterable = SUCCEEDED(
455             d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_FILTER,
456                                     D3DRTYPE_TEXTURE, d3dFormatInfo.texFormat));
457     }
458 
459     if (d3dFormatInfo.renderFormat != D3DFMT_UNKNOWN)
460     {
461         textureCaps.textureAttachment = SUCCEEDED(
462             d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_RENDERTARGET,
463                                     D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
464         if (textureCaps.textureAttachment && (formatInfo.colorEncoding == GL_SRGB))
465         {
466             textureCaps.textureAttachment = SUCCEEDED(d3d9->CheckDeviceFormat(
467                 adapter, deviceType, adapterFormat, D3DUSAGE_QUERY_SRGBWRITE, D3DRTYPE_TEXTURE,
468                 d3dFormatInfo.renderFormat));
469         }
470 
471         if ((formatInfo.depthBits > 0 || formatInfo.stencilBits > 0) &&
472             !textureCaps.textureAttachment)
473         {
474             textureCaps.textureAttachment = SUCCEEDED(
475                 d3d9->CheckDeviceFormat(adapter, deviceType, adapterFormat, D3DUSAGE_DEPTHSTENCIL,
476                                         D3DRTYPE_TEXTURE, d3dFormatInfo.renderFormat));
477         }
478         textureCaps.renderbuffer = textureCaps.textureAttachment;
479         textureCaps.blendable    = textureCaps.renderbuffer;
480 
481         textureCaps.sampleCounts.insert(1);
482         for (unsigned int i = D3DMULTISAMPLE_2_SAMPLES; i <= D3DMULTISAMPLE_16_SAMPLES; i++)
483         {
484             D3DMULTISAMPLE_TYPE multisampleType = D3DMULTISAMPLE_TYPE(i);
485 
486             HRESULT result = d3d9->CheckDeviceMultiSampleType(
487                 adapter, deviceType, d3dFormatInfo.renderFormat, TRUE, multisampleType, nullptr);
488             if (SUCCEEDED(result))
489             {
490                 textureCaps.sampleCounts.insert(i);
491             }
492         }
493     }
494 
495     return textureCaps;
496 }
497 
GenerateCaps(IDirect3D9 * d3d9,IDirect3DDevice9 * device,D3DDEVTYPE deviceType,UINT adapter,gl::Caps * caps,gl::TextureCapsMap * textureCapsMap,gl::Extensions * extensions,gl::Limitations * limitations)498 void GenerateCaps(IDirect3D9 *d3d9,
499                   IDirect3DDevice9 *device,
500                   D3DDEVTYPE deviceType,
501                   UINT adapter,
502                   gl::Caps *caps,
503                   gl::TextureCapsMap *textureCapsMap,
504                   gl::Extensions *extensions,
505                   gl::Limitations *limitations)
506 {
507     D3DCAPS9 deviceCaps;
508     if (FAILED(d3d9->GetDeviceCaps(adapter, deviceType, &deviceCaps)))
509     {
510         // Can't continue with out device caps
511         return;
512     }
513 
514     D3DDISPLAYMODE currentDisplayMode;
515     d3d9->GetAdapterDisplayMode(adapter, &currentDisplayMode);
516 
517     GLuint maxSamples = 0;
518     for (GLenum internalFormat : gl::GetAllSizedInternalFormats())
519     {
520         gl::TextureCaps textureCaps = GenerateTextureFormatCaps(internalFormat, d3d9, deviceType,
521                                                                 adapter, currentDisplayMode.Format);
522         textureCapsMap->insert(internalFormat, textureCaps);
523 
524         maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
525     }
526 
527     // GL core feature limits
528     caps->maxElementIndex = static_cast<GLint64>(std::numeric_limits<unsigned int>::max());
529 
530     // 3D textures are unimplemented in D3D9
531     caps->max3DTextureSize = 1;
532 
533     // Only one limit in GL, use the minimum dimension
534     caps->max2DTextureSize = std::min(deviceCaps.MaxTextureWidth, deviceCaps.MaxTextureHeight);
535 
536     // D3D treats cube maps as a special case of 2D textures
537     caps->maxCubeMapTextureSize = caps->max2DTextureSize;
538 
539     // Array textures are not available in D3D9
540     caps->maxArrayTextureLayers = 1;
541 
542     // ES3-only feature
543     caps->maxLODBias = 0.0f;
544 
545     // No specific limits on render target size, maximum 2D texture size is equivalent
546     caps->maxRenderbufferSize = caps->max2DTextureSize;
547 
548     // Draw buffers are not supported in D3D9
549     caps->maxDrawBuffers      = 1;
550     caps->maxColorAttachments = 1;
551 
552     // No specific limits on viewport size, maximum 2D texture size is equivalent
553     caps->maxViewportWidth  = caps->max2DTextureSize;
554     caps->maxViewportHeight = caps->maxViewportWidth;
555 
556     // Point size is clamped to 1.0f when the shader model is less than 3
557     caps->minAliasedPointSize = 1.0f;
558     caps->maxAliasedPointSize =
559         ((D3DSHADER_VERSION_MAJOR(deviceCaps.PixelShaderVersion) >= 3) ? deviceCaps.MaxPointSize
560                                                                        : 1.0f);
561 
562     // Wide lines not supported
563     caps->minAliasedLineWidth = 1.0f;
564     caps->maxAliasedLineWidth = 1.0f;
565 
566     // Primitive count limits (unused in ES2)
567     caps->maxElementsIndices  = 0;
568     caps->maxElementsVertices = 0;
569 
570     // Program and shader binary formats (no supported shader binary formats)
571     caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
572 
573     caps->vertexHighpFloat.setIEEEFloat();
574     caps->vertexMediumpFloat.setIEEEFloat();
575     caps->vertexLowpFloat.setIEEEFloat();
576     caps->fragmentHighpFloat.setIEEEFloat();
577     caps->fragmentMediumpFloat.setIEEEFloat();
578     caps->fragmentLowpFloat.setIEEEFloat();
579 
580     // Some (most) hardware only supports single-precision floating-point numbers,
581     // which can accurately represent integers up to +/-16777216
582     caps->vertexHighpInt.setSimulatedInt(24);
583     caps->vertexMediumpInt.setSimulatedInt(24);
584     caps->vertexLowpInt.setSimulatedInt(24);
585     caps->fragmentHighpInt.setSimulatedInt(24);
586     caps->fragmentMediumpInt.setSimulatedInt(24);
587     caps->fragmentLowpInt.setSimulatedInt(24);
588 
589     // WaitSync is ES3-only, set to zero
590     caps->maxServerWaitTimeout = 0;
591 
592     // Vertex shader limits
593     caps->maxVertexAttributes = 16;
594     // Vertex Attrib Binding not supported.
595     caps->maxVertexAttribBindings = caps->maxVertexAttributes;
596 
597     const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
598     caps->maxVertexUniformVectors =
599         MAX_VERTEX_CONSTANT_VECTORS_D3D9 - GetReservedVertexUniformVectors();
600     caps->maxShaderUniformComponents[gl::ShaderType::Vertex] = caps->maxVertexUniformVectors * 4;
601 
602     caps->maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0;
603 
604     // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE.
605     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors();
606     const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors();
607     caps->maxVertexOutputComponents =
608         ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
609                                                                  : MAX_VERTEX_OUTPUT_VECTORS_SM2) *
610         4;
611 
612     // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
613     // We test this using D3D9 by checking support for the R16F format.
614     if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) &&
615         SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format,
616                                           D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE,
617                                           D3DFMT_R16F)))
618     {
619         const size_t MAX_TEXTURE_IMAGE_UNITS_VTF_SM3             = 4;
620         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = MAX_TEXTURE_IMAGE_UNITS_VTF_SM3;
621     }
622     else
623     {
624         caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] = 0;
625     }
626 
627     // Fragment shader limits
628     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM3 = 224;
629     const size_t MAX_PIXEL_CONSTANT_VECTORS_SM2 = 32;
630     caps->maxFragmentUniformVectors =
631         ((deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0)) ? MAX_PIXEL_CONSTANT_VECTORS_SM3
632                                                                 : MAX_PIXEL_CONSTANT_VECTORS_SM2) -
633         GetReservedFragmentUniformVectors();
634     caps->maxShaderUniformComponents[gl::ShaderType::Fragment] =
635         caps->maxFragmentUniformVectors * 4;
636     caps->maxShaderUniformBlocks[gl::ShaderType::Fragment]     = 0;
637     caps->maxFragmentInputComponents                           = caps->maxVertexOutputComponents;
638     caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment] = 16;
639     caps->minProgramTexelOffset                                = 0;
640     caps->maxProgramTexelOffset                                = 0;
641 
642     // Aggregate shader limits (unused in ES2)
643     caps->maxUniformBufferBindings                                     = 0;
644     caps->maxUniformBlockSize                                          = 0;
645     caps->uniformBufferOffsetAlignment                                 = 0;
646     caps->maxCombinedUniformBlocks                                     = 0;
647     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Vertex]   = 0;
648     caps->maxCombinedShaderUniformComponents[gl::ShaderType::Fragment] = 0;
649     caps->maxVaryingComponents                                         = 0;
650 
651     // Aggregate shader limits
652     caps->maxVaryingVectors            = caps->maxVertexOutputComponents / 4;
653     caps->maxCombinedTextureImageUnits = caps->maxShaderTextureImageUnits[gl::ShaderType::Vertex] +
654                                          caps->maxShaderTextureImageUnits[gl::ShaderType::Fragment];
655 
656     // Transform feedback limits
657     caps->maxTransformFeedbackInterleavedComponents = 0;
658     caps->maxTransformFeedbackSeparateAttributes    = 0;
659     caps->maxTransformFeedbackSeparateComponents    = 0;
660 
661     // Multisample limits
662     caps->maxSamples = maxSamples;
663 
664     // GL extension support
665     extensions->setTextureExtensionSupport(*textureCapsMap);
666     extensions->elementIndexUintOES = deviceCaps.MaxVertexIndex >= (1 << 16);
667     extensions->getProgramBinaryOES = true;
668     extensions->rgb8Rgba8OES        = true;
669     extensions->readFormatBgraEXT   = true;
670     extensions->pixelBufferObjectNV = false;
671     extensions->mapbufferOES        = false;
672     extensions->mapBufferRangeEXT   = false;
673 
674     // D3D does not allow depth textures to have more than one mipmap level OES_depth_texture
675     // allows for that so we can't implement full support with the D3D9 back end.
676     extensions->depthTextureOES = false;
677 
678     // textureRgEXT is emulated and not performant.
679     extensions->textureRgEXT = false;
680 
681     // GL_KHR_parallel_shader_compile
682     extensions->parallelShaderCompileKHR = true;
683 
684     D3DADAPTER_IDENTIFIER9 adapterId = {};
685     if (SUCCEEDED(d3d9->GetAdapterIdentifier(adapter, 0, &adapterId)))
686     {
687         // ATI cards on XP have problems with non-power-of-two textures.
688         extensions->textureNpotOES =
689             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
690             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
691             !(deviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) &&
692             !(!IsWindowsVistaOrLater() && IsAMD(adapterId.VendorId));
693 
694         // Disable depth texture support on AMD cards (See ANGLE issue 839)
695         if (IsAMD(adapterId.VendorId))
696         {
697             extensions->depthTextureANGLE = false;
698             extensions->depthTextureOES   = false;
699         }
700     }
701     else
702     {
703         extensions->textureNpotOES = false;
704     }
705 
706     extensions->drawBuffersEXT    = false;
707     extensions->textureStorageEXT = true;
708 
709     // Must support a minimum of 2:1 anisotropy for max anisotropy to be considered supported, per
710     // the spec
711     extensions->textureFilterAnisotropicEXT =
712         (deviceCaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) != 0 && deviceCaps.MaxAnisotropy >= 2;
713     caps->maxTextureAnisotropy = static_cast<GLfloat>(deviceCaps.MaxAnisotropy);
714 
715     // Check occlusion query support by trying to create one
716     IDirect3DQuery9 *occlusionQuery = nullptr;
717     extensions->occlusionQueryBooleanEXT =
718         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery)) && occlusionQuery;
719     SafeRelease(occlusionQuery);
720 
721     // Check event query support by trying to create one
722     IDirect3DQuery9 *eventQuery = nullptr;
723     extensions->fenceNV =
724         SUCCEEDED(device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery)) && eventQuery;
725     SafeRelease(eventQuery);
726 
727     extensions->disjointTimerQueryEXT = false;
728     extensions->robustnessEXT         = true;
729     // It seems that only DirectX 10 and higher enforce the well-defined behavior of always
730     // returning zero values when out-of-bounds reads. See
731     // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt
732     extensions->robustBufferAccessBehaviorKHR = false;
733     extensions->blendMinmaxEXT                = true;
734     // Although according to
735     // https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware
736     // D3D9 doesn't have full blending capability for RGBA32F. But turns out it could provide
737     // correct blending result in reality. As a result of some regression reports by client app, we
738     // decided to turn floatBlendEXT on for D3D9
739     extensions->floatBlendEXT               = true;
740     extensions->framebufferBlitANGLE        = true;
741     extensions->framebufferMultisampleANGLE = true;
742     extensions->instancedArraysANGLE        = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
743     // D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT
744     // extension
745     extensions->instancedArraysEXT       = false;
746     extensions->packReverseRowOrderANGLE = true;
747     extensions->standardDerivativesOES =
748         (deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
749     extensions->shaderTextureLodEXT         = true;
750     extensions->fragDepthEXT                = true;
751     extensions->textureUsageANGLE           = true;
752     extensions->translatedShaderSourceANGLE = true;
753     extensions->fboRenderMipmapOES          = true;
754     extensions->textureMirrorClampToEdgeEXT = true;
755     extensions->discardFramebufferEXT = false;  // It would be valid to set this to true, since
756                                                 // glDiscardFramebufferEXT is just a hint
757     extensions->colorBufferFloatEXT   = false;
758     extensions->debugMarkerEXT        = true;
759     extensions->EGLImageOES           = true;
760     extensions->EGLImageExternalOES   = true;
761     extensions->unpackSubimageEXT     = true;
762     extensions->packSubimageNV        = true;
763     extensions->syncQueryCHROMIUM     = extensions->fenceNV;
764     extensions->copyTextureCHROMIUM   = true;
765     extensions->textureBorderClampEXT = true;
766     extensions->textureBorderClampOES = true;
767     extensions->videoTextureWEBGL     = true;
768 
769     // D3D9 has no concept of separate masks and refs for front and back faces in the depth stencil
770     // state.
771     limitations->noSeparateStencilRefsAndMasks = true;
772 
773     // D3D9 shader models have limited support for looping, so the Appendix A
774     // index/loop limitations are necessary. Workarounds that are needed to
775     // support dynamic indexing of vectors on HLSL also don't work on D3D9.
776     limitations->shadersRequireIndexedLoopValidation = true;
777 
778     // D3D9 cannot support constant color and alpha blend funcs together
779     limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
780 
781     // D3D9 cannot support unclamped constant blend color
782     limitations->noUnclampedBlendColor = true;
783 
784     // D3D9 cannot support packing more than one variable to a single varying.
785     // TODO(jmadill): Implement more sophisticated component packing in D3D9.
786     limitations->noFlexibleVaryingPacking = true;
787 
788     // D3D9 does not support vertex attribute aliasing
789     limitations->noVertexAttributeAliasing = true;
790 
791     // D3D9 does not support compressed textures where the base mip level is not a multiple of 4
792     limitations->compressedBaseMipLevelMultipleOfFour = true;
793 }
794 
795 }  // namespace d3d9_gl
796 
797 namespace d3d9
798 {
799 
ComputeBlockSize(D3DFORMAT format,GLuint width,GLuint height)800 GLuint ComputeBlockSize(D3DFORMAT format, GLuint width, GLuint height)
801 {
802     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
803     GLuint numBlocksWide  = (width + d3dFormatInfo.blockWidth - 1) / d3dFormatInfo.blockWidth;
804     GLuint numBlocksHight = (height + d3dFormatInfo.blockHeight - 1) / d3dFormatInfo.blockHeight;
805     return (d3dFormatInfo.pixelBytes * numBlocksWide * numBlocksHight);
806 }
807 
MakeValidSize(bool isImage,D3DFORMAT format,GLsizei * requestWidth,GLsizei * requestHeight,int * levelOffset)808 void MakeValidSize(bool isImage,
809                    D3DFORMAT format,
810                    GLsizei *requestWidth,
811                    GLsizei *requestHeight,
812                    int *levelOffset)
813 {
814     const D3DFormat &d3dFormatInfo = d3d9::GetD3DFormatInfo(format);
815 
816     int upsampleCount = 0;
817     // Don't expand the size of full textures that are at least (blockWidth x blockHeight) already.
818     if (isImage || *requestWidth < static_cast<GLsizei>(d3dFormatInfo.blockWidth) ||
819         *requestHeight < static_cast<GLsizei>(d3dFormatInfo.blockHeight))
820     {
821         while (*requestWidth % d3dFormatInfo.blockWidth != 0 ||
822                *requestHeight % d3dFormatInfo.blockHeight != 0)
823         {
824             *requestWidth <<= 1;
825             *requestHeight <<= 1;
826             upsampleCount++;
827         }
828     }
829     *levelOffset = upsampleCount;
830 }
831 
InitializeFeatures(angle::FeaturesD3D * features,DWORD vendorID)832 void InitializeFeatures(angle::FeaturesD3D *features, DWORD vendorID)
833 {
834     ANGLE_FEATURE_CONDITION(features, mrtPerfWorkaround, true);
835     ANGLE_FEATURE_CONDITION(features, setDataFasterThanImageUpload, false);
836     ANGLE_FEATURE_CONDITION(features, useInstancedPointSpriteEmulation, false);
837 
838     // TODO(jmadill): Disable workaround when we have a fixed compiler DLL.
839     ANGLE_FEATURE_CONDITION(features, expandIntegerPowExpressions, true);
840 
841     // crbug.com/1011627 Turn this on for D3D9.
842     ANGLE_FEATURE_CONDITION(features, allowClearForRobustResourceInit, true);
843 
844     ANGLE_FEATURE_CONDITION(features, borderColorSrgb, IsNvidia(vendorID));
845 }
846 
847 }  // namespace d3d9
848 
849 }  // namespace rx
850