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