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