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