1 //
2 // Copyright 2013 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 // formatutils9.cpp: Queries for GL image formats and their translations to D3D9
8 // formats.
9
10 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
11
12 #include "image_util/copyimage.h"
13 #include "image_util/generatemip.h"
14 #include "image_util/loadimage.h"
15
16 #include "anglebase/no_destructor.h"
17 #include "libANGLE/renderer/d3d/d3d9/Renderer9.h"
18 #include "libANGLE/renderer/d3d/d3d9/vertexconversion.h"
19
20 using namespace angle;
21
22 namespace rx
23 {
24
25 namespace d3d9
26 {
27
28 constexpr D3DFORMAT D3DFMT_INTZ = ((D3DFORMAT)(MAKEFOURCC('I', 'N', 'T', 'Z')));
29 constexpr D3DFORMAT D3DFMT_NULL = ((D3DFORMAT)(MAKEFOURCC('N', 'U', 'L', 'L')));
30
31 // A map to determine the pixel size and mip generation function of a given D3D format
32 typedef std::map<D3DFORMAT, D3DFormat> D3D9FormatInfoMap;
33
34 typedef std::pair<GLint, InitializeTextureDataFunction> InternalFormatInitialzerPair;
35 typedef std::map<GLint, InitializeTextureDataFunction> InternalFormatInitialzerMap;
36
BuildInternalFormatInitialzerMap()37 static InternalFormatInitialzerMap BuildInternalFormatInitialzerMap()
38 {
39 using namespace angle; // For image initialization functions
40
41 InternalFormatInitialzerMap map;
42
43 map.insert(InternalFormatInitialzerPair(
44 GL_RGB16F, Initialize4ComponentData<GLhalf, 0x0000, 0x0000, 0x0000, gl::Float16One>));
45 map.insert(InternalFormatInitialzerPair(
46 GL_RGB32F,
47 Initialize4ComponentData<GLfloat, 0x00000000, 0x00000000, 0x00000000, gl::Float32One>));
48
49 return map;
50 }
51
UnreachableLoad(size_t width,size_t height,size_t depth,const uint8_t * input,size_t inputRowPitch,size_t inputDepthPitch,uint8_t * output,size_t outputRowPitch,size_t outputDepthPitch)52 static void UnreachableLoad(size_t width,
53 size_t height,
54 size_t depth,
55 const uint8_t *input,
56 size_t inputRowPitch,
57 size_t inputDepthPitch,
58 uint8_t *output,
59 size_t outputRowPitch,
60 size_t outputDepthPitch)
61 {
62 UNREACHABLE();
63 }
64
65 typedef std::pair<GLenum, TextureFormat> D3D9FormatPair;
66 typedef std::map<GLenum, TextureFormat> D3D9FormatMap;
67
TextureFormat()68 TextureFormat::TextureFormat()
69 : texFormat(D3DFMT_UNKNOWN),
70 renderFormat(D3DFMT_UNKNOWN),
71 dataInitializerFunction(nullptr),
72 loadFunction(UnreachableLoad)
73 {}
74
InsertD3D9FormatInfo(D3D9FormatMap * map,GLenum internalFormat,D3DFORMAT texFormat,D3DFORMAT renderFormat,LoadImageFunction loadFunction)75 static inline void InsertD3D9FormatInfo(D3D9FormatMap *map,
76 GLenum internalFormat,
77 D3DFORMAT texFormat,
78 D3DFORMAT renderFormat,
79 LoadImageFunction loadFunction)
80 {
81 TextureFormat info;
82 info.texFormat = texFormat;
83 info.renderFormat = renderFormat;
84
85 static const angle::base::NoDestructor<InternalFormatInitialzerMap> dataInitializationMap(
86 BuildInternalFormatInitialzerMap());
87 InternalFormatInitialzerMap::const_iterator dataInitIter =
88 dataInitializationMap->find(internalFormat);
89 info.dataInitializerFunction =
90 (dataInitIter != dataInitializationMap->end()) ? dataInitIter->second : nullptr;
91
92 info.loadFunction = loadFunction;
93
94 map->insert(std::make_pair(internalFormat, info));
95 }
96
BuildD3D9FormatMap()97 static D3D9FormatMap BuildD3D9FormatMap()
98 {
99 using namespace angle; // For image loading functions
100
101 D3D9FormatMap map;
102
103 // clang-format off
104 // | Internal format | Texture format | Render format | Load function |
105 InsertD3D9FormatInfo(&map, GL_NONE, D3DFMT_NULL, D3DFMT_NULL, UnreachableLoad );
106
107 // We choose to downsample the GL_DEPTH_COMPONENT32_OES format to a 24-bit format because D3DFMT_D32 is not widely
108 // supported. We're allowed to do this because:
109 // - The ES spec 2.0.25 sec 3.7.1 states that we're allowed to store texture formats with internal format
110 // resolutions of our own choosing.
111 // - OES_depth_texture states that downsampling of the depth formats is allowed.
112 // - ANGLE_depth_texture does not state minimum required resolutions of the depth texture formats it
113 // introduces.
114 // In ES3 however, there are minimum resolutions for the texture formats and this would not be allowed.
115
116 InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT16, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad );
117 InsertD3D9FormatInfo(&map, GL_DEPTH_COMPONENT32_OES, D3DFMT_INTZ, D3DFMT_D24X8, UnreachableLoad );
118 InsertD3D9FormatInfo(&map, GL_DEPTH24_STENCIL8_OES, D3DFMT_INTZ, D3DFMT_D24S8, UnreachableLoad );
119 InsertD3D9FormatInfo(&map, GL_STENCIL_INDEX8, D3DFMT_UNKNOWN, D3DFMT_D24S8, UnreachableLoad ); // TODO: What's the texture format?
120
121 InsertD3D9FormatInfo(&map, GL_RGBA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative<GLfloat, 4> );
122 InsertD3D9FormatInfo(&map, GL_RGB32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_A32B32G32R32F, LoadToNative3To4<GLfloat, gl::Float32One>);
123 InsertD3D9FormatInfo(&map, GL_RG32F_EXT, D3DFMT_G32R32F, D3DFMT_G32R32F, LoadToNative<GLfloat, 2> );
124 InsertD3D9FormatInfo(&map, GL_R32F_EXT, D3DFMT_R32F, D3DFMT_R32F, LoadToNative<GLfloat, 1> );
125 InsertD3D9FormatInfo(&map, GL_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadA32FToRGBA32F );
126 InsertD3D9FormatInfo(&map, GL_LUMINANCE32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadL32FToRGBA32F );
127 InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA32F_EXT, D3DFMT_A32B32G32R32F, D3DFMT_UNKNOWN, LoadLA32FToRGBA32F );
128
129 InsertD3D9FormatInfo(&map, GL_RGBA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative<GLhalf, 4> );
130 InsertD3D9FormatInfo(&map, GL_RGB16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_A16B16G16R16F, LoadToNative3To4<GLhalf, gl::Float16One> );
131 InsertD3D9FormatInfo(&map, GL_RG16F_EXT, D3DFMT_G16R16F, D3DFMT_G16R16F, LoadToNative<GLhalf, 2> );
132 InsertD3D9FormatInfo(&map, GL_R16F_EXT, D3DFMT_R16F, D3DFMT_R16F, LoadToNative<GLhalf, 1> );
133 InsertD3D9FormatInfo(&map, GL_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadA16FToRGBA16F );
134 InsertD3D9FormatInfo(&map, GL_LUMINANCE16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadL16FToRGBA16F );
135 InsertD3D9FormatInfo(&map, GL_LUMINANCE_ALPHA16F_EXT, D3DFMT_A16B16G16R16F, D3DFMT_UNKNOWN, LoadLA16FToRGBA16F );
136
137 InsertD3D9FormatInfo(&map, GL_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadA8ToBGRA8 );
138
139 InsertD3D9FormatInfo(&map, GL_RGB8_OES, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRGB8ToBGRX8 );
140 InsertD3D9FormatInfo(&map, GL_RGB565, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR5G6B5ToBGRA8 );
141 InsertD3D9FormatInfo(&map, GL_RGBA8_OES, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 );
142 InsertD3D9FormatInfo(&map, GL_RGBA4, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA4ToBGRA8 );
143 InsertD3D9FormatInfo(&map, GL_RGB5_A1, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGB5A1ToBGRA8 );
144 InsertD3D9FormatInfo(&map, GL_R8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadR8ToBGRX8 );
145 InsertD3D9FormatInfo(&map, GL_RG8_EXT, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, LoadRG8ToBGRX8 );
146
147 InsertD3D9FormatInfo(&map, GL_SRGB8, D3DFMT_X8R8G8B8, D3DFMT_UNKNOWN, LoadRGB8ToBGRX8 );
148 InsertD3D9FormatInfo(&map, GL_SRGB8_ALPHA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadRGBA8ToBGRA8 );
149
150 InsertD3D9FormatInfo(&map, GL_BGRA8_EXT, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadToNative<GLubyte, 4> );
151 InsertD3D9FormatInfo(&map, GL_BGRA4_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGRA4ToBGRA8 );
152 InsertD3D9FormatInfo(&map, GL_BGR5_A1_ANGLEX, D3DFMT_A8R8G8B8, D3DFMT_A8R8G8B8, LoadBGR5A1ToBGRA8 );
153
154 InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> );
155 InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> );
156 InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 16> );
157 InsertD3D9FormatInfo(&map, GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 16> );
158
159 InsertD3D9FormatInfo(&map, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> );
160 InsertD3D9FormatInfo(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, D3DFMT_DXT1, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 8> );
161 InsertD3D9FormatInfo(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, D3DFMT_DXT3, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 16> );
162 InsertD3D9FormatInfo(&map, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, D3DFMT_DXT5, D3DFMT_UNKNOWN, LoadCompressedToNative<4, 4, 1, 16> );
163
164 // These formats require checking if the renderer supports D3DFMT_L8 or D3DFMT_A8L8 and
165 // then changing the format and loading function appropriately.
166 InsertD3D9FormatInfo(&map, GL_LUMINANCE8_EXT, D3DFMT_L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 1> );
167 InsertD3D9FormatInfo(&map, GL_LUMINANCE8_ALPHA8_EXT, D3DFMT_A8L8, D3DFMT_UNKNOWN, LoadToNative<GLubyte, 2> );
168 // clang-format on
169
170 return map;
171 }
172
GetTextureFormatInfo(GLenum internalFormat)173 const TextureFormat &GetTextureFormatInfo(GLenum internalFormat)
174 {
175 static const angle::base::NoDestructor<D3D9FormatMap> formatMap(BuildD3D9FormatMap());
176 D3D9FormatMap::const_iterator iter = formatMap->find(internalFormat);
177 if (iter != formatMap->end())
178 {
179 return iter->second;
180 }
181 else
182 {
183 static const TextureFormat defaultInfo;
184 return defaultInfo;
185 }
186 }
187
GetDeclTypeComponentType(D3DDECLTYPE declType)188 static GLenum GetDeclTypeComponentType(D3DDECLTYPE declType)
189 {
190 switch (declType)
191 {
192 case D3DDECLTYPE_FLOAT1:
193 return GL_FLOAT;
194 case D3DDECLTYPE_FLOAT2:
195 return GL_FLOAT;
196 case D3DDECLTYPE_FLOAT3:
197 return GL_FLOAT;
198 case D3DDECLTYPE_FLOAT4:
199 return GL_FLOAT;
200 case D3DDECLTYPE_UBYTE4:
201 return GL_UNSIGNED_INT;
202 case D3DDECLTYPE_SHORT2:
203 return GL_INT;
204 case D3DDECLTYPE_SHORT4:
205 return GL_INT;
206 case D3DDECLTYPE_UBYTE4N:
207 return GL_UNSIGNED_NORMALIZED;
208 case D3DDECLTYPE_SHORT4N:
209 return GL_SIGNED_NORMALIZED;
210 case D3DDECLTYPE_USHORT4N:
211 return GL_UNSIGNED_NORMALIZED;
212 case D3DDECLTYPE_SHORT2N:
213 return GL_SIGNED_NORMALIZED;
214 case D3DDECLTYPE_USHORT2N:
215 return GL_UNSIGNED_NORMALIZED;
216 default:
217 UNREACHABLE();
218 return GL_NONE;
219 }
220 }
221
222 // Attribute format conversion
223 enum
224 {
225 NUM_GL_VERTEX_ATTRIB_TYPES = 6
226 };
227
228 struct TranslationDescription
229 {
230 DWORD capsFlag;
231 VertexFormat preferredConversion;
232 VertexFormat fallbackConversion;
233 };
234
235 // Mapping from OpenGL-ES vertex attrib type to D3D decl type:
236 //
237 // BYTE SHORT (Cast)
238 // BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
239 // UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
240 // UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
241 // SHORT SHORT (Identity)
242 // SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
243 // UNSIGNED_SHORT FLOAT (Cast)
244 // UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
245 // FIXED (not in WebGL) FLOAT (FixedToFloat)
246 // FLOAT FLOAT (Identity)
247
248 // GLToCType maps from GL type (as GLenum) to the C typedef.
249 template <GLenum GLType>
250 struct GLToCType
251 {};
252
253 template <>
254 struct GLToCType<GL_BYTE>
255 {
256 typedef GLbyte type;
257 };
258 template <>
259 struct GLToCType<GL_UNSIGNED_BYTE>
260 {
261 typedef GLubyte type;
262 };
263 template <>
264 struct GLToCType<GL_SHORT>
265 {
266 typedef GLshort type;
267 };
268 template <>
269 struct GLToCType<GL_UNSIGNED_SHORT>
270 {
271 typedef GLushort type;
272 };
273 template <>
274 struct GLToCType<GL_FIXED>
275 {
276 typedef GLuint type;
277 };
278 template <>
279 struct GLToCType<GL_FLOAT>
280 {
281 typedef GLfloat type;
282 };
283
284 // This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
285 enum D3DVertexType
286 {
287 D3DVT_FLOAT,
288 D3DVT_SHORT,
289 D3DVT_SHORT_NORM,
290 D3DVT_UBYTE,
291 D3DVT_UBYTE_NORM,
292 D3DVT_USHORT_NORM
293 };
294
295 // D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
296 template <unsigned int D3DType>
297 struct D3DToCType
298 {};
299
300 template <>
301 struct D3DToCType<D3DVT_FLOAT>
302 {
303 typedef float type;
304 };
305 template <>
306 struct D3DToCType<D3DVT_SHORT>
307 {
308 typedef short type;
309 };
310 template <>
311 struct D3DToCType<D3DVT_SHORT_NORM>
312 {
313 typedef short type;
314 };
315 template <>
316 struct D3DToCType<D3DVT_UBYTE>
317 {
318 typedef unsigned char type;
319 };
320 template <>
321 struct D3DToCType<D3DVT_UBYTE_NORM>
322 {
323 typedef unsigned char type;
324 };
325 template <>
326 struct D3DToCType<D3DVT_USHORT_NORM>
327 {
328 typedef unsigned short type;
329 };
330
331 // Encode the type/size combinations that D3D permits. For each type/size it expands to a widener
332 // that will provide the appropriate final size.
333 template <unsigned int type, int size>
334 struct WidenRule
335 {};
336
337 template <int size>
338 struct WidenRule<D3DVT_FLOAT, size> : NoWiden<size>
339 {};
340 template <int size>
341 struct WidenRule<D3DVT_SHORT, size> : WidenToEven<size>
342 {};
343 template <int size>
344 struct WidenRule<D3DVT_SHORT_NORM, size> : WidenToEven<size>
345 {};
346 template <int size>
347 struct WidenRule<D3DVT_UBYTE, size> : WidenToFour<size>
348 {};
349 template <int size>
350 struct WidenRule<D3DVT_UBYTE_NORM, size> : WidenToFour<size>
351 {};
352 template <int size>
353 struct WidenRule<D3DVT_USHORT_NORM, size> : WidenToEven<size>
354 {};
355
356 // VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D
357 // vertex type & size combination.
358 template <unsigned int d3dtype, int size>
359 struct VertexTypeFlags
360 {};
361
362 template <unsigned int _capflag, unsigned int _declflag>
363 struct VertexTypeFlagsHelper
364 {
365 enum
366 {
367 capflag = _capflag
368 };
369 enum
370 {
371 declflag = _declflag
372 };
373 };
374
375 template <>
376 struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1>
377 {};
378 template <>
379 struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2>
380 {};
381 template <>
382 struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3>
383 {};
384 template <>
385 struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4>
386 {};
387 template <>
388 struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2>
389 {};
390 template <>
391 struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4>
392 {};
393 template <>
394 struct VertexTypeFlags<D3DVT_SHORT_NORM, 2>
395 : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N>
396 {};
397 template <>
398 struct VertexTypeFlags<D3DVT_SHORT_NORM, 4>
399 : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N>
400 {};
401 template <>
402 struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4>
403 {};
404 template <>
405 struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4>
406 : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N>
407 {};
408 template <>
409 struct VertexTypeFlags<D3DVT_USHORT_NORM, 2>
410 : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N>
411 {};
412 template <>
413 struct VertexTypeFlags<D3DVT_USHORT_NORM, 4>
414 : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N>
415 {};
416
417 // VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as
418 // D3DVertexType enums).
419 template <GLenum GLtype, bool normalized>
420 struct VertexTypeMapping
421 {};
422
423 template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
424 struct VertexTypeMappingBase
425 {
426 enum
427 {
428 preferred = Preferred
429 };
430 enum
431 {
432 fallback = Fallback
433 };
434 };
435
436 template <>
437 struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT>
438 {}; // Cast
439 template <>
440 struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT>
441 {}; // Normalize
442 template <>
443 struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT>
444 {}; // Identity, Cast
445 template <>
446 struct VertexTypeMapping<GL_UNSIGNED_BYTE, true>
447 : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT>
448 {}; // Identity, Normalize
449 template <>
450 struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT>
451 {}; // Identity
452 template <>
453 struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT>
454 {}; // Cast, Normalize
455 template <>
456 struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT>
457 {}; // Cast
458 template <>
459 struct VertexTypeMapping<GL_UNSIGNED_SHORT, true>
460 : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT>
461 {}; // Cast, Normalize
462 template <bool normalized>
463 struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT>
464 {}; // FixedToFloat
465 template <bool normalized>
466 struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT>
467 {}; // Identity
468
469 // Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule
470 // (Cast, Normalize, Identity, FixedToFloat). The conversion rules themselves are defined in
471 // vertexconversion.h.
472
473 // Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T>
474 // knows it's an identity mapping).
475 template <GLenum fromType, bool normalized, unsigned int toType>
476 struct ConversionRule : Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
477 {};
478
479 // All conversions from normalized types to float use the Normalize operator.
480 template <GLenum fromType>
481 struct ConversionRule<fromType, true, D3DVT_FLOAT> : Normalize<typename GLToCType<fromType>::type>
482 {};
483
484 // Use a full specialization for this so that it preferentially matches ahead of the generic
485 // normalize-to-float rules.
486 template <>
487 struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : FixedToFloat<GLint, 16>
488 {};
489 template <>
490 struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : FixedToFloat<GLint, 16>
491 {};
492
493 // A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues
494 // (i.e. 0/1) whether it is normalized or not.
495 template <class T, bool normalized>
496 struct DefaultVertexValuesStage2
497 {};
498
499 template <class T>
500 struct DefaultVertexValuesStage2<T, true> : NormalizedDefaultValues<T>
501 {};
502 template <class T>
503 struct DefaultVertexValuesStage2<T, false> : SimpleDefaultValues<T>
504 {};
505
506 // Work out the default value rule for a D3D type (expressed as the C type) and
507 template <class T, bool normalized>
508 struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
509 {};
510 template <bool normalized>
511 struct DefaultVertexValues<float, normalized> : SimpleDefaultValues<float>
512 {};
513
514 // Policy rules for use with Converter, to choose whether to use the preferred or fallback
515 // conversion. The fallback conversion produces an output that all D3D9 devices must support.
516 template <class T>
517 struct UsePreferred
518 {
519 enum
520 {
521 type = T::preferred
522 };
523 };
524 template <class T>
525 struct UseFallback
526 {
527 enum
528 {
529 type = T::fallback
530 };
531 };
532
533 // Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback
534 // conversion, it provides all the members of the appropriate VertexDataConverter, the
535 // D3DCAPS9::DeclTypes flag in cap flag and the D3DDECLTYPE member needed for the vertex declaration
536 // in declflag.
537 template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
538 struct Converter
539 : VertexDataConverter<
540 typename GLToCType<fromType>::type,
541 WidenRule<PreferenceRule<VertexTypeMapping<fromType, normalized>>::type, size>,
542 ConversionRule<fromType,
543 normalized,
544 PreferenceRule<VertexTypeMapping<fromType, normalized>>::type>,
545 DefaultVertexValues<typename D3DToCType<PreferenceRule<
546 VertexTypeMapping<fromType, normalized>>::type>::type,
547 normalized>>
548 {
549 private:
550 enum
551 {
552 d3dtype = PreferenceRule<VertexTypeMapping<fromType, normalized>>::type
553 };
554 enum
555 {
556 d3dsize = WidenRule<d3dtype, size>::finalWidth
557 };
558
559 public:
560 enum
561 {
562 capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag
563 };
564 enum
565 {
566 declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag
567 };
568 };
569
VertexFormat()570 VertexFormat::VertexFormat()
571 : conversionType(VERTEX_CONVERT_NONE),
572 outputElementSize(0),
573 copyFunction(nullptr),
574 nativeFormat(D3DDECLTYPE_UNUSED),
575 componentType(GL_NONE)
576 {}
577
578 // Initialize a TranslationInfo
CreateVertexFormatInfo(bool identity,size_t elementSize,VertexCopyFunction copyFunc,D3DDECLTYPE nativeFormat)579 VertexFormat CreateVertexFormatInfo(bool identity,
580 size_t elementSize,
581 VertexCopyFunction copyFunc,
582 D3DDECLTYPE nativeFormat)
583 {
584 VertexFormat formatInfo;
585 formatInfo.conversionType = identity ? VERTEX_CONVERT_NONE : VERTEX_CONVERT_CPU;
586 formatInfo.outputElementSize = elementSize;
587 formatInfo.copyFunction = copyFunc;
588 formatInfo.nativeFormat = nativeFormat;
589 formatInfo.componentType = GetDeclTypeComponentType(nativeFormat);
590 return formatInfo;
591 }
592
593 #define TRANSLATION(type, norm, size, preferred) \
594 CreateVertexFormatInfo( \
595 Converter<type, norm, size, preferred>::identity, \
596 Converter<type, norm, size, preferred>::finalSize, \
597 Converter<type, norm, size, preferred>::convertArray, \
598 static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag))
599
600 #define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
601 { \
602 Converter<type, norm, size, UsePreferred>::capflag, \
603 TRANSLATION(type, norm, size, UsePreferred), \
604 TRANSLATION(type, norm, size, UseFallback) \
605 }
606
607 #define TRANSLATIONS_FOR_TYPE(type) \
608 { \
609 {TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), \
610 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), \
611 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), \
612 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4)}, \
613 {TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), \
614 TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), \
615 TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), \
616 TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4)}, \
617 }
618
619 #define TRANSLATIONS_FOR_TYPE_NO_NORM(type) \
620 { \
621 {TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), \
622 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), \
623 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), \
624 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4)}, \
625 {TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), \
626 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), \
627 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), \
628 TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4)}, \
629 }
630
ComputeTypeIndex(GLenum type)631 static inline unsigned int ComputeTypeIndex(GLenum type)
632 {
633 switch (type)
634 {
635 case GL_BYTE:
636 return 0;
637 case GL_UNSIGNED_BYTE:
638 return 1;
639 case GL_SHORT:
640 return 2;
641 case GL_UNSIGNED_SHORT:
642 return 3;
643 case GL_FIXED:
644 return 4;
645 case GL_FLOAT:
646 return 5;
647
648 default:
649 UNREACHABLE();
650 return 5;
651 }
652 }
653
GetVertexFormatInfo(DWORD supportedDeclTypes,angle::FormatID vertexFormatID)654 const VertexFormat &GetVertexFormatInfo(DWORD supportedDeclTypes, angle::FormatID vertexFormatID)
655 {
656 static DWORD initializedDeclTypes = 0;
657 static VertexFormat formatConverters[NUM_GL_VERTEX_ATTRIB_TYPES][2][4];
658 if (initializedDeclTypes != supportedDeclTypes)
659 {
660 const TranslationDescription
661 translations[NUM_GL_VERTEX_ATTRIB_TYPES][2]
662 [4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
663 {TRANSLATIONS_FOR_TYPE(GL_BYTE), TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
664 TRANSLATIONS_FOR_TYPE(GL_SHORT), TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
665 TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FIXED), TRANSLATIONS_FOR_TYPE_NO_NORM(GL_FLOAT)};
666 for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
667 {
668 for (unsigned int j = 0; j < 2; j++)
669 {
670 for (unsigned int k = 0; k < 4; k++)
671 {
672 if (translations[i][j][k].capsFlag == 0 ||
673 (supportedDeclTypes & translations[i][j][k].capsFlag) != 0)
674 {
675 formatConverters[i][j][k] = translations[i][j][k].preferredConversion;
676 }
677 else
678 {
679 formatConverters[i][j][k] = translations[i][j][k].fallbackConversion;
680 }
681 }
682 }
683 }
684 initializedDeclTypes = supportedDeclTypes;
685 }
686
687 const gl::VertexFormat &vertexFormat = gl::GetVertexFormatFromID(vertexFormatID);
688
689 // Pure integer attributes only supported in ES3.0
690 ASSERT(!vertexFormat.pureInteger);
691 return formatConverters[ComputeTypeIndex(vertexFormat.type)][vertexFormat.normalized]
692 [vertexFormat.components - 1];
693 }
694 } // namespace d3d9
695 } // namespace rx
696