1#include "precompiled.h"
2//
3// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// renderer9_utils.cpp: Conversion functions and other utility routines
9// specific to the D3D9 renderer.
10
11#include "libGLESv2/renderer/renderer9_utils.h"
12#include "libGLESv2/mathutil.h"
13#include "libGLESv2/Context.h"
14
15#include "common/debug.h"
16
17namespace gl_d3d9
18{
19
20D3DCMPFUNC ConvertComparison(GLenum comparison)
21{
22    D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
23    switch (comparison)
24    {
25      case GL_NEVER:    d3dComp = D3DCMP_NEVER;        break;
26      case GL_ALWAYS:   d3dComp = D3DCMP_ALWAYS;       break;
27      case GL_LESS:     d3dComp = D3DCMP_LESS;         break;
28      case GL_LEQUAL:   d3dComp = D3DCMP_LESSEQUAL;    break;
29      case GL_EQUAL:    d3dComp = D3DCMP_EQUAL;        break;
30      case GL_GREATER:  d3dComp = D3DCMP_GREATER;      break;
31      case GL_GEQUAL:   d3dComp = D3DCMP_GREATEREQUAL; break;
32      case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL;     break;
33      default: UNREACHABLE();
34    }
35
36    return d3dComp;
37}
38
39D3DCOLOR ConvertColor(gl::Color color)
40{
41    return D3DCOLOR_RGBA(gl::unorm<8>(color.red),
42                         gl::unorm<8>(color.green),
43                         gl::unorm<8>(color.blue),
44                         gl::unorm<8>(color.alpha));
45}
46
47D3DBLEND ConvertBlendFunc(GLenum blend)
48{
49    D3DBLEND d3dBlend = D3DBLEND_ZERO;
50
51    switch (blend)
52    {
53      case GL_ZERO:                     d3dBlend = D3DBLEND_ZERO;           break;
54      case GL_ONE:                      d3dBlend = D3DBLEND_ONE;            break;
55      case GL_SRC_COLOR:                d3dBlend = D3DBLEND_SRCCOLOR;       break;
56      case GL_ONE_MINUS_SRC_COLOR:      d3dBlend = D3DBLEND_INVSRCCOLOR;    break;
57      case GL_DST_COLOR:                d3dBlend = D3DBLEND_DESTCOLOR;      break;
58      case GL_ONE_MINUS_DST_COLOR:      d3dBlend = D3DBLEND_INVDESTCOLOR;   break;
59      case GL_SRC_ALPHA:                d3dBlend = D3DBLEND_SRCALPHA;       break;
60      case GL_ONE_MINUS_SRC_ALPHA:      d3dBlend = D3DBLEND_INVSRCALPHA;    break;
61      case GL_DST_ALPHA:                d3dBlend = D3DBLEND_DESTALPHA;      break;
62      case GL_ONE_MINUS_DST_ALPHA:      d3dBlend = D3DBLEND_INVDESTALPHA;   break;
63      case GL_CONSTANT_COLOR:           d3dBlend = D3DBLEND_BLENDFACTOR;    break;
64      case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
65      case GL_CONSTANT_ALPHA:           d3dBlend = D3DBLEND_BLENDFACTOR;    break;
66      case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
67      case GL_SRC_ALPHA_SATURATE:       d3dBlend = D3DBLEND_SRCALPHASAT;    break;
68      default: UNREACHABLE();
69    }
70
71    return d3dBlend;
72}
73
74D3DBLENDOP ConvertBlendOp(GLenum blendOp)
75{
76    D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
77
78    switch (blendOp)
79    {
80      case GL_FUNC_ADD:              d3dBlendOp = D3DBLENDOP_ADD;         break;
81      case GL_FUNC_SUBTRACT:         d3dBlendOp = D3DBLENDOP_SUBTRACT;    break;
82      case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break;
83      default: UNREACHABLE();
84    }
85
86    return d3dBlendOp;
87}
88
89D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
90{
91    D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
92
93    switch (stencilOp)
94    {
95      case GL_ZERO:      d3dStencilOp = D3DSTENCILOP_ZERO;    break;
96      case GL_KEEP:      d3dStencilOp = D3DSTENCILOP_KEEP;    break;
97      case GL_REPLACE:   d3dStencilOp = D3DSTENCILOP_REPLACE; break;
98      case GL_INCR:      d3dStencilOp = D3DSTENCILOP_INCRSAT; break;
99      case GL_DECR:      d3dStencilOp = D3DSTENCILOP_DECRSAT; break;
100      case GL_INVERT:    d3dStencilOp = D3DSTENCILOP_INVERT;  break;
101      case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR;    break;
102      case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR;    break;
103      default: UNREACHABLE();
104    }
105
106    return d3dStencilOp;
107}
108
109D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
110{
111    D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
112
113    switch (wrap)
114    {
115      case GL_REPEAT:            d3dWrap = D3DTADDRESS_WRAP;   break;
116      case GL_CLAMP_TO_EDGE:     d3dWrap = D3DTADDRESS_CLAMP;  break;
117      case GL_MIRRORED_REPEAT:   d3dWrap = D3DTADDRESS_MIRROR; break;
118      default: UNREACHABLE();
119    }
120
121    return d3dWrap;
122}
123
124D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
125{
126    D3DCULL cull = D3DCULL_CCW;
127    switch (cullFace)
128    {
129      case GL_FRONT:
130        cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
131        break;
132      case GL_BACK:
133        cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
134        break;
135      case GL_FRONT_AND_BACK:
136        cull = D3DCULL_NONE; // culling will be handled during draw
137        break;
138      default: UNREACHABLE();
139    }
140
141    return cull;
142}
143
144D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
145{
146    D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
147
148    switch (cubeFace)
149    {
150      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
151        face = D3DCUBEMAP_FACE_POSITIVE_X;
152        break;
153      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
154        face = D3DCUBEMAP_FACE_NEGATIVE_X;
155        break;
156      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
157        face = D3DCUBEMAP_FACE_POSITIVE_Y;
158        break;
159      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
160        face = D3DCUBEMAP_FACE_NEGATIVE_Y;
161        break;
162      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
163        face = D3DCUBEMAP_FACE_POSITIVE_Z;
164        break;
165      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
166        face = D3DCUBEMAP_FACE_NEGATIVE_Z;
167        break;
168      default: UNREACHABLE();
169    }
170
171    return face;
172}
173
174DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
175{
176    return (red   ? D3DCOLORWRITEENABLE_RED   : 0) |
177           (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
178           (blue  ? D3DCOLORWRITEENABLE_BLUE  : 0) |
179           (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
180}
181
182D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter, float maxAnisotropy)
183{
184    if (maxAnisotropy > 1.0f)
185    {
186        return D3DTEXF_ANISOTROPIC;
187    }
188
189    D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
190    switch (magFilter)
191    {
192      case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT;  break;
193      case GL_LINEAR:  d3dMagFilter = D3DTEXF_LINEAR; break;
194      default: UNREACHABLE();
195    }
196
197    return d3dMagFilter;
198}
199
200void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter, float maxAnisotropy)
201{
202    switch (minFilter)
203    {
204      case GL_NEAREST:
205        *d3dMinFilter = D3DTEXF_POINT;
206        *d3dMipFilter = D3DTEXF_NONE;
207        break;
208      case GL_LINEAR:
209        *d3dMinFilter = D3DTEXF_LINEAR;
210        *d3dMipFilter = D3DTEXF_NONE;
211        break;
212      case GL_NEAREST_MIPMAP_NEAREST:
213        *d3dMinFilter = D3DTEXF_POINT;
214        *d3dMipFilter = D3DTEXF_POINT;
215        break;
216      case GL_LINEAR_MIPMAP_NEAREST:
217        *d3dMinFilter = D3DTEXF_LINEAR;
218        *d3dMipFilter = D3DTEXF_POINT;
219        break;
220      case GL_NEAREST_MIPMAP_LINEAR:
221        *d3dMinFilter = D3DTEXF_POINT;
222        *d3dMipFilter = D3DTEXF_LINEAR;
223        break;
224      case GL_LINEAR_MIPMAP_LINEAR:
225        *d3dMinFilter = D3DTEXF_LINEAR;
226        *d3dMipFilter = D3DTEXF_LINEAR;
227        break;
228      default:
229        *d3dMinFilter = D3DTEXF_POINT;
230        *d3dMipFilter = D3DTEXF_NONE;
231        UNREACHABLE();
232    }
233
234    if (maxAnisotropy > 1.0f)
235    {
236        *d3dMinFilter = D3DTEXF_ANISOTROPIC;
237    }
238}
239
240D3DFORMAT ConvertRenderbufferFormat(GLenum format)
241{
242    switch (format)
243    {
244      case GL_NONE:                 return D3DFMT_NULL;
245      case GL_RGBA4:
246      case GL_RGB5_A1:
247      case GL_RGBA8_OES:            return D3DFMT_A8R8G8B8;
248      case GL_RGB565:               return D3DFMT_R5G6B5;
249      case GL_RGB8_OES:             return D3DFMT_X8R8G8B8;
250      case GL_DEPTH_COMPONENT16:
251      case GL_STENCIL_INDEX8:
252      case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
253      default: UNREACHABLE();       return D3DFMT_A8R8G8B8;
254    }
255}
256
257D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
258{
259    if (samples <= 1)
260        return D3DMULTISAMPLE_NONE;
261    else
262        return (D3DMULTISAMPLE_TYPE)samples;
263}
264
265}
266
267namespace d3d9_gl
268{
269
270unsigned int GetStencilSize(D3DFORMAT stencilFormat)
271{
272    if (stencilFormat == D3DFMT_INTZ)
273    {
274        return 8;
275    }
276    switch(stencilFormat)
277    {
278      case D3DFMT_D24FS8:
279      case D3DFMT_D24S8:
280        return 8;
281      case D3DFMT_D24X4S4:
282        return 4;
283      case D3DFMT_D15S1:
284        return 1;
285      case D3DFMT_D16_LOCKABLE:
286      case D3DFMT_D32:
287      case D3DFMT_D24X8:
288      case D3DFMT_D32F_LOCKABLE:
289      case D3DFMT_D16:
290        return 0;
291    //case D3DFMT_D32_LOCKABLE:  return 0;   // DirectX 9Ex only
292    //case D3DFMT_S8_LOCKABLE:   return 8;   // DirectX 9Ex only
293      default:
294        return 0;
295    }
296}
297
298unsigned int GetAlphaSize(D3DFORMAT colorFormat)
299{
300    switch (colorFormat)
301    {
302      case D3DFMT_A16B16G16R16F:
303        return 16;
304      case D3DFMT_A32B32G32R32F:
305        return 32;
306      case D3DFMT_A2R10G10B10:
307        return 2;
308      case D3DFMT_A8R8G8B8:
309        return 8;
310      case D3DFMT_A1R5G5B5:
311        return 1;
312      case D3DFMT_X8R8G8B8:
313      case D3DFMT_R5G6B5:
314        return 0;
315      default:
316        return 0;
317    }
318}
319
320GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type)
321{
322    if (type == D3DMULTISAMPLE_NONMASKABLE)
323        return 0;
324    else
325        return type;
326}
327
328bool IsFormatChannelEquivalent(D3DFORMAT d3dformat, GLenum format)
329{
330    switch (d3dformat)
331    {
332      case D3DFMT_L8:
333        return (format == GL_LUMINANCE);
334      case D3DFMT_A8L8:
335        return (format == GL_LUMINANCE_ALPHA);
336      case D3DFMT_DXT1:
337        return (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
338      case D3DFMT_DXT3:
339        return (format == GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE);
340      case D3DFMT_DXT5:
341        return (format == GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE);
342      case D3DFMT_A8R8G8B8:
343      case D3DFMT_A16B16G16R16F:
344      case D3DFMT_A32B32G32R32F:
345        return (format == GL_RGBA || format == GL_BGRA_EXT);
346      case D3DFMT_X8R8G8B8:
347        return (format == GL_RGB);
348      default:
349        if (d3dformat == D3DFMT_INTZ && gl::IsDepthTexture(format))
350            return true;
351        return false;
352    }
353}
354
355GLenum ConvertBackBufferFormat(D3DFORMAT format)
356{
357    switch (format)
358    {
359      case D3DFMT_A4R4G4B4: return GL_RGBA4;
360      case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
361      case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
362      case D3DFMT_R5G6B5:   return GL_RGB565;
363      case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
364      default:
365        UNREACHABLE();
366    }
367
368    return GL_RGBA4;
369}
370
371GLenum ConvertDepthStencilFormat(D3DFORMAT format)
372{
373    if (format == D3DFMT_INTZ)
374    {
375        return GL_DEPTH24_STENCIL8_OES;
376    }
377    switch (format)
378    {
379      case D3DFMT_D16:
380      case D3DFMT_D24X8:
381        return GL_DEPTH_COMPONENT16;
382      case D3DFMT_D24S8:
383        return GL_DEPTH24_STENCIL8_OES;
384      case D3DFMT_UNKNOWN:
385        return GL_NONE;
386      default:
387        UNREACHABLE();
388    }
389
390    return GL_DEPTH24_STENCIL8_OES;
391}
392
393GLenum ConvertRenderTargetFormat(D3DFORMAT format)
394{
395    if (format == D3DFMT_INTZ)
396    {
397        return GL_DEPTH24_STENCIL8_OES;
398    }
399
400    switch (format)
401    {
402      case D3DFMT_A4R4G4B4: return GL_RGBA4;
403      case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
404      case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
405      case D3DFMT_R5G6B5:   return GL_RGB565;
406      case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
407      case D3DFMT_D16:
408      case D3DFMT_D24X8:
409        return GL_DEPTH_COMPONENT16;
410      case D3DFMT_D24S8:
411        return GL_DEPTH24_STENCIL8_OES;
412      case D3DFMT_UNKNOWN:
413        return GL_NONE;
414      default:
415        UNREACHABLE();
416    }
417
418    return GL_RGBA4;
419}
420
421GLenum GetEquivalentFormat(D3DFORMAT format)
422{
423    if (format == D3DFMT_INTZ)
424        return GL_DEPTH24_STENCIL8_OES;
425    if (format == D3DFMT_NULL)
426        return GL_NONE;
427
428    switch (format)
429    {
430      case D3DFMT_A4R4G4B4:             return GL_RGBA4;
431      case D3DFMT_A8R8G8B8:             return GL_RGBA8_OES;
432      case D3DFMT_A1R5G5B5:             return GL_RGB5_A1;
433      case D3DFMT_R5G6B5:               return GL_RGB565;
434      case D3DFMT_X8R8G8B8:             return GL_RGB8_OES;
435      case D3DFMT_D16:                  return GL_DEPTH_COMPONENT16;
436      case D3DFMT_D24S8:                return GL_DEPTH24_STENCIL8_OES;
437      case D3DFMT_UNKNOWN:              return GL_NONE;
438      case D3DFMT_DXT1:                 return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
439      case D3DFMT_DXT3:                 return GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
440      case D3DFMT_DXT5:                 return GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
441      case D3DFMT_A32B32G32R32F:        return GL_RGBA32F_EXT;
442      case D3DFMT_A16B16G16R16F:        return GL_RGBA16F_EXT;
443      case D3DFMT_L8:                   return GL_LUMINANCE8_EXT;
444      case D3DFMT_A8L8:                 return GL_LUMINANCE8_ALPHA8_EXT;
445      default:              UNREACHABLE();
446        return GL_NONE;
447    }
448}
449
450}
451
452namespace d3d9
453{
454
455bool IsCompressedFormat(D3DFORMAT surfaceFormat)
456{
457    switch(surfaceFormat)
458    {
459      case D3DFMT_DXT1:
460      case D3DFMT_DXT2:
461      case D3DFMT_DXT3:
462      case D3DFMT_DXT4:
463      case D3DFMT_DXT5:
464        return true;
465      default:
466        return false;
467    }
468}
469
470size_t ComputeRowSize(D3DFORMAT format, unsigned int width)
471{
472    if (format == D3DFMT_INTZ)
473    {
474        return 4 * width;
475    }
476    switch (format)
477    {
478      case D3DFMT_L8:
479          return 1 * width;
480      case D3DFMT_A8L8:
481          return 2 * width;
482      case D3DFMT_X8R8G8B8:
483      case D3DFMT_A8R8G8B8:
484        return 4 * width;
485      case D3DFMT_A16B16G16R16F:
486        return 8 * width;
487      case D3DFMT_A32B32G32R32F:
488        return 16 * width;
489      case D3DFMT_DXT1:
490        return 8 * ((width + 3) / 4);
491      case D3DFMT_DXT3:
492      case D3DFMT_DXT5:
493        return 16 * ((width + 3) / 4);
494      default:
495        UNREACHABLE();
496        return 0;
497    }
498}
499
500}
501