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, ¤tDisplayMode);
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