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