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