Home | History | Annotate | Download | only in nine
      1 /*
      2  * Copyright 2011 Joakim Sindholt <opensource (at) zhasha.com>
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * on the rights to use, copy, modify, merge, publish, distribute, sub
      8  * license, and/or sell copies of the Software, and to permit persons to whom
      9  * the Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
     19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
     22 
     23 #ifndef _NINE_PIPE_H_
     24 #define _NINE_PIPE_H_
     25 
     26 #include "d3d9.h"
     27 #include "pipe/p_format.h"
     28 #include "pipe/p_screen.h"
     29 #include "pipe/p_state.h" /* pipe_box */
     30 #include "util/macros.h"
     31 #include "util/u_rect.h"
     32 #include "util/u_format.h"
     33 #include "nine_helpers.h"
     34 
     35 struct cso_context;
     36 
     37 extern const enum pipe_format nine_d3d9_to_pipe_format_map[120];
     38 extern const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT];
     39 
     40 void nine_convert_dsa_state(struct pipe_depth_stencil_alpha_state *, const DWORD *);
     41 void nine_convert_rasterizer_state(struct NineDevice9 *, struct pipe_rasterizer_state *, const DWORD *);
     42 void nine_convert_blend_state(struct pipe_blend_state *, const DWORD *);
     43 void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *);
     44 
     45 #define is_ATI1_ATI2(format) (format == PIPE_FORMAT_RGTC1_UNORM || format == PIPE_FORMAT_RGTC2_UNORM)
     46 
     47 static inline void
     48 rect_to_pipe_box(struct pipe_box *dst, const RECT *src)
     49 {
     50     dst->x = src->left;
     51     dst->y = src->top;
     52     dst->z = 0;
     53     dst->width = src->right - src->left;
     54     dst->height = src->bottom - src->top;
     55     dst->depth = 1;
     56 }
     57 
     58 static inline void
     59 pipe_box_to_rect(RECT *dst, const struct pipe_box *src)
     60 {
     61     dst->left = src->x;
     62     dst->right = src->x + src->width;
     63     dst->top = src->y;
     64     dst->bottom = src->y + src->height;
     65 }
     66 
     67 static inline void
     68 rect_minify_inclusive(RECT *rect)
     69 {
     70     rect->left = rect->left >> 2;
     71     rect->top = rect->top >> 2;
     72     rect->right = DIV_ROUND_UP(rect->right, 2);
     73     rect->bottom = DIV_ROUND_UP(rect->bottom, 2);
     74 }
     75 
     76 /* We suppose:
     77  * 0 <= rect->left < rect->right
     78  * 0 <= rect->top < rect->bottom
     79  */
     80 static inline void
     81 fit_rect_format_inclusive(enum pipe_format format, RECT *rect, int width, int height)
     82 {
     83     const unsigned w = util_format_get_blockwidth(format);
     84     const unsigned h = util_format_get_blockheight(format);
     85 
     86     if (util_format_is_compressed(format)) {
     87         rect->left = rect->left - rect->left % w;
     88         rect->top = rect->top - rect->top % h;
     89         rect->right = (rect->right % w) == 0 ?
     90             rect->right :
     91             rect->right - (rect->right % w) + w;
     92         rect->bottom = (rect->bottom % h) == 0 ?
     93             rect->bottom :
     94             rect->bottom - (rect->bottom % h) + h;
     95     }
     96 
     97     rect->right = MIN2(rect->right, width);
     98     rect->bottom = MIN2(rect->bottom, height);
     99 }
    100 
    101 static inline boolean
    102 rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src)
    103 {
    104     rect_to_pipe_box(dst, src);
    105 
    106     if (dst->width <= 0 || dst->height <= 0) {
    107         DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box");
    108         dst->width = MAX2(dst->width, 0);
    109         dst->height = MAX2(dst->height, 0);
    110         return TRUE;
    111     }
    112     return FALSE;
    113 }
    114 
    115 static inline boolean
    116 rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *src)
    117 {
    118     rect_to_pipe_box(dst, src);
    119 
    120     if (dst->width >= 0 && dst->height >= 0)
    121         return FALSE;
    122     if (dst->width < 0) dst->width = -dst->width;
    123     if (dst->height < 0) dst->height = -dst->height;
    124     return TRUE;
    125 }
    126 
    127 static inline void
    128 rect_to_pipe_box_xy_only(struct pipe_box *dst, const RECT *src)
    129 {
    130     user_warn(src->left > src->right || src->top > src->bottom);
    131 
    132     dst->x = src->left;
    133     dst->y = src->top;
    134     dst->width = src->right - src->left;
    135     dst->height = src->bottom - src->top;
    136 }
    137 
    138 static inline boolean
    139 rect_to_pipe_box_xy_only_clamp(struct pipe_box *dst, const RECT *src)
    140 {
    141     rect_to_pipe_box_xy_only(dst, src);
    142 
    143     if (dst->width <= 0 || dst->height <= 0) {
    144         DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box");
    145         dst->width = MAX2(dst->width, 0);
    146         dst->height = MAX2(dst->height, 0);
    147         return TRUE;
    148     }
    149     return FALSE;
    150 }
    151 
    152 static inline void
    153 rect_to_g3d_u_rect(struct u_rect *dst, const RECT *src)
    154 {
    155     user_warn(src->left > src->right || src->top > src->bottom);
    156 
    157     dst->x0 = src->left;
    158     dst->x1 = src->right;
    159     dst->y0 = src->top;
    160     dst->y1 = src->bottom;
    161 }
    162 
    163 static inline void
    164 d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src)
    165 {
    166     user_warn(src->Left > src->Right);
    167     user_warn(src->Top > src->Bottom);
    168     user_warn(src->Front > src->Back);
    169 
    170     dst->x = src->Left;
    171     dst->y = src->Top;
    172     dst->z = src->Front;
    173     dst->width = src->Right - src->Left;
    174     dst->height = src->Bottom - src->Top;
    175     dst->depth = src->Back - src->Front;
    176 }
    177 
    178 static inline D3DFORMAT
    179 pipe_to_d3d9_format(enum pipe_format format)
    180 {
    181     return nine_pipe_to_d3d9_format_map[format];
    182 }
    183 
    184 /* ATI1 and ATI2 are not officially compressed in d3d9 */
    185 static inline boolean
    186 compressed_format( D3DFORMAT fmt )
    187 {
    188     switch (fmt) {
    189     case D3DFMT_DXT1:
    190     case D3DFMT_DXT2:
    191     case D3DFMT_DXT3:
    192     case D3DFMT_DXT4:
    193     case D3DFMT_DXT5:
    194         return TRUE;
    195     default:
    196         break;
    197     }
    198     return FALSE;
    199 }
    200 
    201 static inline boolean
    202 depth_stencil_format( D3DFORMAT fmt )
    203 {
    204     static D3DFORMAT allowed[] = {
    205         D3DFMT_D16_LOCKABLE,
    206         D3DFMT_D32,
    207         D3DFMT_D15S1,
    208         D3DFMT_D24S8,
    209         D3DFMT_D24X8,
    210         D3DFMT_D24X4S4,
    211         D3DFMT_D16,
    212         D3DFMT_D32F_LOCKABLE,
    213         D3DFMT_D24FS8,
    214         D3DFMT_D32_LOCKABLE,
    215         D3DFMT_DF16,
    216         D3DFMT_DF24,
    217         D3DFMT_INTZ
    218     };
    219     unsigned i;
    220 
    221     for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) {
    222         if (fmt == allowed[i]) { return TRUE; }
    223     }
    224     return FALSE;
    225 }
    226 
    227 static inline unsigned
    228 d3d9_get_pipe_depth_format_bindings(D3DFORMAT format)
    229 {
    230     switch (format) {
    231     case D3DFMT_D32:
    232     case D3DFMT_D15S1:
    233     case D3DFMT_D24S8:
    234     case D3DFMT_D24X8:
    235     case D3DFMT_D24X4S4:
    236     case D3DFMT_D16:
    237     case D3DFMT_D24FS8:
    238         return PIPE_BIND_DEPTH_STENCIL;
    239     case D3DFMT_D32F_LOCKABLE:
    240     case D3DFMT_D16_LOCKABLE:
    241     case D3DFMT_D32_LOCKABLE:
    242         return PIPE_BIND_DEPTH_STENCIL;
    243     case D3DFMT_DF16:
    244     case D3DFMT_DF24:
    245     case D3DFMT_INTZ:
    246         return PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_SAMPLER_VIEW;
    247     default: unreachable("Unexpected format");
    248     }
    249 }
    250 
    251 static inline enum pipe_format
    252 d3d9_to_pipe_format_internal(D3DFORMAT format)
    253 {
    254     if (format <= D3DFMT_A2B10G10R10_XR_BIAS)
    255         return nine_d3d9_to_pipe_format_map[format];
    256     switch (format) {
    257     case D3DFMT_INTZ: return PIPE_FORMAT_S8_UINT_Z24_UNORM;
    258     case D3DFMT_DF16: return PIPE_FORMAT_Z16_UNORM;
    259     case D3DFMT_DXT1: return PIPE_FORMAT_DXT1_RGBA;
    260     case D3DFMT_DXT2: return PIPE_FORMAT_DXT3_RGBA; /* XXX */
    261     case D3DFMT_DXT3: return PIPE_FORMAT_DXT3_RGBA;
    262     case D3DFMT_DXT4: return PIPE_FORMAT_DXT5_RGBA; /* XXX */
    263     case D3DFMT_DXT5: return PIPE_FORMAT_DXT5_RGBA;
    264     case D3DFMT_ATI1: return PIPE_FORMAT_RGTC1_UNORM;
    265     case D3DFMT_ATI2: return PIPE_FORMAT_RGTC2_UNORM;
    266     case D3DFMT_UYVY: return PIPE_FORMAT_UYVY;
    267     case D3DFMT_YUY2: return PIPE_FORMAT_YUYV; /* XXX check */
    268     case D3DFMT_NV12: return PIPE_FORMAT_NV12;
    269     case D3DFMT_G8R8_G8B8: return PIPE_FORMAT_G8R8_G8B8_UNORM; /* XXX order ? */
    270     case D3DFMT_R8G8_B8G8: return PIPE_FORMAT_R8G8_B8G8_UNORM; /* XXX order ? */
    271     case D3DFMT_BINARYBUFFER: return PIPE_FORMAT_NONE; /* not a format */
    272     case D3DFMT_MULTI2_ARGB8: return PIPE_FORMAT_NONE; /* not supported */
    273     case D3DFMT_Y210: /* XXX */
    274     case D3DFMT_Y216:
    275     case D3DFMT_NV11:
    276     case D3DFMT_DF24: /* Similar to D3DFMT_DF16 but for 24-bits.
    277         We don't advertise it because when it is supported, Fetch-4 is
    278         supposed to be supported, which we don't support yet. */
    279     case D3DFMT_NULL: /* special cased, only for surfaces */
    280         return PIPE_FORMAT_NONE;
    281     default:
    282         DBG_FLAG(DBG_UNKNOWN, "unknown D3DFORMAT: 0x%x/%c%c%c%c\n",
    283                  format, (char)format, (char)(format >> 8),
    284                  (char)(format >> 16), (char)(format >> 24));
    285         return PIPE_FORMAT_NONE;
    286     }
    287 }
    288 
    289 #define format_check_internal(pipe_format) \
    290     screen->is_format_supported(screen, pipe_format, target, \
    291                                 sample_count, bindings)
    292 
    293 static inline enum pipe_format
    294 d3d9_to_pipe_format_checked(struct pipe_screen *screen,
    295                             D3DFORMAT format,
    296                             enum pipe_texture_target target,
    297                             unsigned sample_count,
    298                             unsigned bindings,
    299                             boolean srgb,
    300                             boolean bypass_check)
    301 {
    302     enum pipe_format result;
    303 
    304     result = d3d9_to_pipe_format_internal(format);
    305     if (result == PIPE_FORMAT_NONE)
    306         return PIPE_FORMAT_NONE;
    307 
    308     if (srgb)
    309         result = util_format_srgb(result);
    310 
    311     /* bypass_check: Used for D3DPOOL_SCRATCH, which
    312      * isn't limited to the formats supported by the
    313      * device, and to check we are not using a format
    314      * fallback. */
    315     if (bypass_check || format_check_internal(result))
    316         return result;
    317 
    318     /* fallback to another format for formats
    319      * that match several pipe_format */
    320     switch(format) {
    321         /* depth buffer formats are not lockable (except those for which it
    322          * is precised in the name), so it is ok to match to another similar
    323          * format. In all cases, if the app reads the texture with a shader,
    324          * it gets depth on r and doesn't get stencil.*/
    325         case D3DFMT_INTZ:
    326         case D3DFMT_D24S8:
    327             if (format_check_internal(PIPE_FORMAT_Z24_UNORM_S8_UINT))
    328                 return PIPE_FORMAT_Z24_UNORM_S8_UINT;
    329             break;
    330         case D3DFMT_D24X8:
    331             if (format_check_internal(PIPE_FORMAT_Z24X8_UNORM))
    332                 return PIPE_FORMAT_Z24X8_UNORM;
    333             break;
    334         /* Support for X8L8V8U8 bumpenvmap format with lighting bits.
    335          * X8L8V8U8 is commonly supported among dx9 cards.
    336          * To avoid precision loss, we use PIPE_FORMAT_R32G32B32X32_FLOAT,
    337          * however using PIPE_FORMAT_R8G8B8A8_SNORM should be ok */
    338         case D3DFMT_X8L8V8U8:
    339             if (bindings & PIPE_BIND_RENDER_TARGET)
    340                 return PIPE_FORMAT_NONE;
    341             if (format_check_internal(PIPE_FORMAT_R32G32B32X32_FLOAT))
    342                 return PIPE_FORMAT_R32G32B32X32_FLOAT;
    343         default:
    344             break;
    345     }
    346     return PIPE_FORMAT_NONE;
    347 }
    348 
    349 /* The quality levels are vendor dependent, so we set our own.
    350  * Every quality level has its own sample count and sample
    351  * position matrix.
    352  * The exact mapping might differ from system to system but thats OK,
    353  * as there's no way to gather more information about quality levels
    354  * in D3D9.
    355  * In case of NONMASKABLE multisample map every quality-level
    356  * to a MASKABLE MultiSampleType:
    357  *  0: no MSAA
    358  *  1: 2x MSAA
    359  *  2: 4x MSAA
    360  *  ...
    361  *  If the requested quality level is not available to nearest
    362  *  matching quality level is used.
    363  *  If no multisample is available the function sets
    364  *  multisample to D3DMULTISAMPLE_NONE and returns zero.
    365  */
    366 static inline HRESULT
    367 d3dmultisample_type_check(struct pipe_screen *screen,
    368                           D3DFORMAT format,
    369                           D3DMULTISAMPLE_TYPE *multisample,
    370                           DWORD multisamplequality,
    371                           DWORD *levels)
    372 {
    373     unsigned bind, i;
    374 
    375     assert(multisample);
    376 
    377     if (levels)
    378         *levels = 1;
    379 
    380     if (*multisample == D3DMULTISAMPLE_NONMASKABLE) {
    381         if (depth_stencil_format(format))
    382             bind = d3d9_get_pipe_depth_format_bindings(format);
    383         else /* render-target */
    384             bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
    385 
    386         *multisample = 0;
    387         for (i = D3DMULTISAMPLE_2_SAMPLES; i < D3DMULTISAMPLE_16_SAMPLES &&
    388             multisamplequality; ++i) {
    389             if (d3d9_to_pipe_format_checked(screen, format, PIPE_TEXTURE_2D,
    390                     i, bind, FALSE, FALSE) != PIPE_FORMAT_NONE) {
    391                 multisamplequality--;
    392                 if (levels)
    393                     (*levels)++;
    394                 *multisample = i;
    395             }
    396         }
    397     }
    398     /* Make sure to get an exact match */
    399     if (multisamplequality)
    400         return D3DERR_INVALIDCALL;
    401     return D3D_OK;
    402 }
    403 
    404 static inline const char *
    405 d3dformat_to_string(D3DFORMAT fmt)
    406 {
    407     switch (fmt) {
    408     case D3DFMT_UNKNOWN: return "D3DFMT_UNKNOWN";
    409     case D3DFMT_R8G8B8: return "D3DFMT_R8G8B8";
    410     case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8";
    411     case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8";
    412     case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5";
    413     case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5";
    414     case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5";
    415     case D3DFMT_A4R4G4B4: return "D3DFMT_A4R4G4B4";
    416     case D3DFMT_R3G3B2: return "D3DFMT_R3G3B2";
    417     case D3DFMT_A8: return "D3DFMT_A8";
    418     case D3DFMT_A8R3G3B2: return "D3DFMT_A8R3G3B2";
    419     case D3DFMT_X4R4G4B4: return "D3DFMT_X4R4G4B4";
    420     case D3DFMT_A2B10G10R10: return "D3DFMT_A2B10G10R10";
    421     case D3DFMT_A8B8G8R8: return "D3DFMT_A8B8G8R8";
    422     case D3DFMT_X8B8G8R8: return "D3DFMT_X8B8G8R8";
    423     case D3DFMT_G16R16: return "D3DFMT_G16R16";
    424     case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10";
    425     case D3DFMT_A16B16G16R16: return "D3DFMT_A16B16G16R16";
    426     case D3DFMT_A8P8: return "D3DFMT_A8P8";
    427     case D3DFMT_P8: return "D3DFMT_P8";
    428     case D3DFMT_L8: return "D3DFMT_L8";
    429     case D3DFMT_A8L8: return "D3DFMT_A8L8";
    430     case D3DFMT_A4L4: return "D3DFMT_A4L4";
    431     case D3DFMT_V8U8: return "D3DFMT_V8U8";
    432     case D3DFMT_L6V5U5: return "D3DFMT_L6V5U5";
    433     case D3DFMT_X8L8V8U8: return "D3DFMT_X8L8V8U8";
    434     case D3DFMT_Q8W8V8U8: return "D3DFMT_Q8W8V8U8";
    435     case D3DFMT_V16U16: return "D3DFMT_V16U16";
    436     case D3DFMT_A2W10V10U10: return "D3DFMT_A2W10V10U10";
    437     case D3DFMT_UYVY: return "D3DFMT_UYVY";
    438     case D3DFMT_R8G8_B8G8: return "D3DFMT_R8G8_B8G8";
    439     case D3DFMT_YUY2: return "D3DFMT_YUY2";
    440     case D3DFMT_G8R8_G8B8: return "D3DFMT_G8R8_G8B8";
    441     case D3DFMT_DXT1: return "D3DFMT_DXT1";
    442     case D3DFMT_DXT2: return "D3DFMT_DXT2";
    443     case D3DFMT_DXT3: return "D3DFMT_DXT3";
    444     case D3DFMT_DXT4: return "D3DFMT_DXT4";
    445     case D3DFMT_DXT5: return "D3DFMT_DXT5";
    446     case D3DFMT_ATI1: return "D3DFMT_ATI1";
    447     case D3DFMT_ATI2: return "D3DFMT_ATI2";
    448     case D3DFMT_D16_LOCKABLE: return "D3DFMT_D16_LOCKABLE";
    449     case D3DFMT_D32: return "D3DFMT_D32";
    450     case D3DFMT_D15S1: return "D3DFMT_D15S1";
    451     case D3DFMT_D24S8: return "D3DFMT_D24S8";
    452     case D3DFMT_D24X8: return "D3DFMT_D24X8";
    453     case D3DFMT_D24X4S4: return "D3DFMT_D24X4S4";
    454     case D3DFMT_D16: return "D3DFMT_D16";
    455     case D3DFMT_D32F_LOCKABLE: return "D3DFMT_D32F_LOCKABLE";
    456     case D3DFMT_D24FS8: return "D3DFMT_D24FS8";
    457     case D3DFMT_D32_LOCKABLE: return "D3DFMT_D32_LOCKABLE";
    458     case D3DFMT_S8_LOCKABLE: return "D3DFMT_S8_LOCKABLE";
    459     case D3DFMT_L16: return "D3DFMT_L16";
    460     case D3DFMT_VERTEXDATA: return "D3DFMT_VERTEXDATA";
    461     case D3DFMT_INDEX16: return "D3DFMT_INDEX16";
    462     case D3DFMT_INDEX32: return "D3DFMT_INDEX32";
    463     case D3DFMT_Q16W16V16U16: return "D3DFMT_Q16W16V16U16";
    464     case D3DFMT_MULTI2_ARGB8: return "D3DFMT_MULTI2_ARGB8";
    465     case D3DFMT_R16F: return "D3DFMT_R16F";
    466     case D3DFMT_G16R16F: return "D3DFMT_G16R16F";
    467     case D3DFMT_A16B16G16R16F: return "D3DFMT_A16B16G16R16F";
    468     case D3DFMT_R32F: return "D3DFMT_R32F";
    469     case D3DFMT_G32R32F: return "D3DFMT_G32R32F";
    470     case D3DFMT_A32B32G32R32F: return "D3DFMT_A32B32G32R32F";
    471     case D3DFMT_CxV8U8: return "D3DFMT_CxV8U8";
    472     case D3DFMT_A1: return "D3DFMT_A1";
    473     case D3DFMT_A2B10G10R10_XR_BIAS: return "D3DFMT_A2B10G10R10_XR_BIAS";
    474     case D3DFMT_BINARYBUFFER: return "D3DFMT_BINARYBUFFER";
    475     case D3DFMT_DF16: return "D3DFMT_DF16";
    476     case D3DFMT_DF24: return "D3DFMT_DF24";
    477     case D3DFMT_INTZ: return "D3DFMT_INTZ";
    478     case D3DFMT_NVDB: return "D3DFMT_NVDB";
    479     case D3DFMT_RESZ: return "D3DFMT_RESZ";
    480     case D3DFMT_NULL: return "D3DFMT_NULL";
    481     case D3DFMT_ATOC: return "D3DFMT_ATOC";
    482     default:
    483         break;
    484     }
    485     return "Unknown";
    486 }
    487 
    488 static inline unsigned
    489 nine_fvf_stride( DWORD fvf )
    490 {
    491     unsigned texcount, i, size = 0;
    492 
    493     switch (fvf & D3DFVF_POSITION_MASK) {
    494     case D3DFVF_XYZ:    size += 3*4; break;
    495     case D3DFVF_XYZRHW: size += 4*4; break;
    496     case D3DFVF_XYZB1:  size += 4*4; break;
    497     case D3DFVF_XYZB2:  size += 5*4; break;
    498     case D3DFVF_XYZB3:  size += 6*4; break;
    499     case D3DFVF_XYZB4:  size += 7*4; break;
    500     case D3DFVF_XYZB5:  size += 8*4; break;
    501     case D3DFVF_XYZW:   size += 4*4; break;
    502     default:
    503         user_warn("Position doesn't match any known combination.");
    504         break;
    505     }
    506 
    507     if (fvf & D3DFVF_NORMAL)   { size += 3*4; }
    508     if (fvf & D3DFVF_PSIZE)    { size += 1*4; }
    509     if (fvf & D3DFVF_DIFFUSE)  { size += 1*4; }
    510     if (fvf & D3DFVF_SPECULAR) { size += 1*4; }
    511 
    512     texcount = (fvf >> D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK;
    513     if (user_error(texcount <= 8))
    514         texcount = 8;
    515 
    516     for (i = 0; i < texcount; ++i) {
    517         unsigned texformat = (fvf>>(16+i*2))&0x3;
    518         /* texformats are defined having been shifted around so 1=3,2=0,3=1,4=2
    519          * meaning we can just do this instead of the switch below */
    520         size += (((texformat+1)&0x3)+1)*4;
    521 
    522         /*
    523         switch (texformat) {
    524         case D3DFVF_TEXTUREFORMAT1: size += 1*4;
    525         case D3DFVF_TEXTUREFORMAT2: size += 2*4;
    526         case D3DFVF_TEXTUREFORMAT3: size += 3*4;
    527         case D3DFVF_TEXTUREFORMAT4: size += 4*4;
    528         }
    529         */
    530     }
    531 
    532     return size;
    533 }
    534 
    535 static inline void
    536 d3dcolor_to_rgba(float *rgba, D3DCOLOR color)
    537 {
    538     rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF;
    539     rgba[1] = (float)((color >>  8) & 0xFF) / 0xFF;
    540     rgba[2] = (float)((color >>  0) & 0xFF) / 0xFF;
    541     rgba[3] = (float)((color >> 24) & 0xFF) / 0xFF;
    542 }
    543 
    544 static inline void
    545 d3dcolor_to_pipe_color_union(union pipe_color_union *rgba, D3DCOLOR color)
    546 {
    547     d3dcolor_to_rgba(&rgba->f[0], color);
    548 }
    549 
    550 static inline unsigned
    551 d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim)
    552 {
    553     switch (prim) {
    554     case D3DPT_POINTLIST:     return PIPE_PRIM_POINTS;
    555     case D3DPT_LINELIST:      return PIPE_PRIM_LINES;
    556     case D3DPT_LINESTRIP:     return PIPE_PRIM_LINE_STRIP;
    557     case D3DPT_TRIANGLELIST:  return PIPE_PRIM_TRIANGLES;
    558     case D3DPT_TRIANGLESTRIP: return PIPE_PRIM_TRIANGLE_STRIP;
    559     case D3DPT_TRIANGLEFAN:   return PIPE_PRIM_TRIANGLE_FAN;
    560     default:
    561         assert(0);
    562         return PIPE_PRIM_POINTS;
    563     }
    564 }
    565 
    566 static inline unsigned
    567 prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count)
    568 {
    569     switch (prim) {
    570     case D3DPT_POINTLIST:     return count;
    571     case D3DPT_LINELIST:      return count * 2;
    572     case D3DPT_LINESTRIP:     return count + 1;
    573     case D3DPT_TRIANGLELIST:  return count * 3;
    574     case D3DPT_TRIANGLESTRIP: return count + 2;
    575     case D3DPT_TRIANGLEFAN:   return count + 2;
    576     default:
    577         assert(0);
    578         return 0;
    579     }
    580 }
    581 
    582 static inline unsigned
    583 d3dcmpfunc_to_pipe_func(D3DCMPFUNC func)
    584 {
    585     switch (func) {
    586     case D3DCMP_NEVER:        return PIPE_FUNC_NEVER;
    587     case D3DCMP_LESS:         return PIPE_FUNC_LESS;
    588     case D3DCMP_EQUAL:        return PIPE_FUNC_EQUAL;
    589     case D3DCMP_LESSEQUAL:    return PIPE_FUNC_LEQUAL;
    590     case D3DCMP_GREATER:      return PIPE_FUNC_GREATER;
    591     case D3DCMP_NOTEQUAL:     return PIPE_FUNC_NOTEQUAL;
    592     case D3DCMP_GREATEREQUAL: return PIPE_FUNC_GEQUAL;
    593     case D3DCMP_ALWAYS:       return PIPE_FUNC_ALWAYS;
    594     case D3DCMP_NEVER_ZERO:   return PIPE_FUNC_NEVER; // Tested on windows + ATI HD5770
    595     default:
    596         assert(0);
    597         return PIPE_FUNC_NEVER;
    598     }
    599 }
    600 
    601 static inline unsigned
    602 d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op)
    603 {
    604     switch (op) {
    605     case D3DSTENCILOP_KEEP:    return PIPE_STENCIL_OP_KEEP;
    606     case D3DSTENCILOP_ZERO:    return PIPE_STENCIL_OP_ZERO;
    607     case D3DSTENCILOP_REPLACE: return PIPE_STENCIL_OP_REPLACE;
    608     case D3DSTENCILOP_INCRSAT: return PIPE_STENCIL_OP_INCR;
    609     case D3DSTENCILOP_DECRSAT: return PIPE_STENCIL_OP_DECR;
    610     case D3DSTENCILOP_INVERT:  return PIPE_STENCIL_OP_INVERT;
    611     case D3DSTENCILOP_INCR:    return PIPE_STENCIL_OP_INCR_WRAP;
    612     case D3DSTENCILOP_DECR:    return PIPE_STENCIL_OP_DECR_WRAP;
    613     default:
    614         return PIPE_STENCIL_OP_ZERO;
    615     }
    616 }
    617 
    618 static inline unsigned
    619 d3dcull_to_pipe_face(D3DCULL cull)
    620 {
    621     switch (cull) {
    622     case D3DCULL_NONE: return PIPE_FACE_NONE;
    623     case D3DCULL_CW:   return PIPE_FACE_FRONT;
    624     case D3DCULL_CCW:  return PIPE_FACE_BACK;
    625     default:
    626         assert(0);
    627         return PIPE_FACE_NONE;
    628     }
    629 }
    630 
    631 static inline unsigned
    632 d3dfillmode_to_pipe_polygon_mode(D3DFILLMODE mode)
    633 {
    634     switch (mode) {
    635     case D3DFILL_POINT:     return PIPE_POLYGON_MODE_POINT;
    636     case D3DFILL_WIREFRAME: return PIPE_POLYGON_MODE_LINE;
    637     case D3DFILL_SOLID:     return PIPE_POLYGON_MODE_FILL;
    638     case D3DFILL_SOLID_ZERO:return PIPE_POLYGON_MODE_FILL;
    639     default:
    640         assert(0);
    641         return PIPE_POLYGON_MODE_FILL;
    642     }
    643 }
    644 
    645 static inline unsigned
    646 d3dblendop_to_pipe_blend(D3DBLENDOP op)
    647 {
    648     switch (op) {
    649     case D3DBLENDOP_ADD:         return PIPE_BLEND_ADD;
    650     case D3DBLENDOP_SUBTRACT:    return PIPE_BLEND_SUBTRACT;
    651     case D3DBLENDOP_REVSUBTRACT: return PIPE_BLEND_REVERSE_SUBTRACT;
    652     case D3DBLENDOP_MIN:         return PIPE_BLEND_MIN;
    653     case D3DBLENDOP_MAX:         return PIPE_BLEND_MAX;
    654     default:
    655         assert(0);
    656         return PIPE_BLEND_ADD;
    657     }
    658 }
    659 
    660 /* NOTE: The COLOR factors for are equal to the ALPHA ones for alpha.
    661  * Drivers may check RGB and ALPHA factors for equality so we should not
    662  * simply substitute the ALPHA variants.
    663  */
    664 static inline unsigned
    665 d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b)
    666 {
    667     switch (b) {
    668     case D3DBLEND_ZERO:            return PIPE_BLENDFACTOR_ZERO;
    669     case D3DBLEND_ONE:             return PIPE_BLENDFACTOR_ONE;
    670     case D3DBLEND_SRCCOLOR:        return PIPE_BLENDFACTOR_SRC_COLOR/*ALPHA*/;
    671     case D3DBLEND_INVSRCCOLOR:     return PIPE_BLENDFACTOR_INV_SRC_COLOR/*ALPHA*/;
    672     case D3DBLEND_SRCALPHA:        return PIPE_BLENDFACTOR_SRC_ALPHA;
    673     case D3DBLEND_INVSRCALPHA:     return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
    674     case D3DBLEND_DESTALPHA:       return PIPE_BLENDFACTOR_DST_ALPHA;
    675     case D3DBLEND_INVDESTALPHA:    return PIPE_BLENDFACTOR_INV_DST_ALPHA;
    676     case D3DBLEND_DESTCOLOR:       return PIPE_BLENDFACTOR_DST_COLOR/*ALPHA*/;
    677     case D3DBLEND_INVDESTCOLOR:    return PIPE_BLENDFACTOR_INV_DST_COLOR/*ALPHA*/;
    678     case D3DBLEND_SRCALPHASAT:     return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
    679     case D3DBLEND_BOTHSRCALPHA:    return PIPE_BLENDFACTOR_SRC_ALPHA;
    680     case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
    681     case D3DBLEND_BLENDFACTOR:     return PIPE_BLENDFACTOR_CONST_COLOR/*ALPHA*/;
    682     case D3DBLEND_INVBLENDFACTOR:  return PIPE_BLENDFACTOR_INV_CONST_COLOR/*ALPHA*/;
    683     case D3DBLEND_SRCCOLOR2:       return PIPE_BLENDFACTOR_ONE; /* XXX */
    684     case D3DBLEND_INVSRCCOLOR2:    return PIPE_BLENDFACTOR_ZERO; /* XXX */
    685     default:
    686        DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b);
    687        return PIPE_BLENDFACTOR_ZERO;
    688     }
    689 }
    690 
    691 static inline unsigned
    692 d3dblend_color_to_pipe_blendfactor(D3DBLEND b)
    693 {
    694     switch (b) {
    695     case D3DBLEND_ZERO:            return PIPE_BLENDFACTOR_ZERO;
    696     case D3DBLEND_ONE:             return PIPE_BLENDFACTOR_ONE;
    697     case D3DBLEND_SRCCOLOR:        return PIPE_BLENDFACTOR_SRC_COLOR;
    698     case D3DBLEND_INVSRCCOLOR:     return PIPE_BLENDFACTOR_INV_SRC_COLOR;
    699     case D3DBLEND_SRCALPHA:        return PIPE_BLENDFACTOR_SRC_ALPHA;
    700     case D3DBLEND_INVSRCALPHA:     return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
    701     case D3DBLEND_DESTALPHA:       return PIPE_BLENDFACTOR_DST_ALPHA;
    702     case D3DBLEND_INVDESTALPHA:    return PIPE_BLENDFACTOR_INV_DST_ALPHA;
    703     case D3DBLEND_DESTCOLOR:       return PIPE_BLENDFACTOR_DST_COLOR;
    704     case D3DBLEND_INVDESTCOLOR:    return PIPE_BLENDFACTOR_INV_DST_COLOR;
    705     case D3DBLEND_SRCALPHASAT:     return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE;
    706     case D3DBLEND_BOTHSRCALPHA:    return PIPE_BLENDFACTOR_SRC_ALPHA;
    707     case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA;
    708     case D3DBLEND_BLENDFACTOR:     return PIPE_BLENDFACTOR_CONST_COLOR;
    709     case D3DBLEND_INVBLENDFACTOR:  return PIPE_BLENDFACTOR_INV_CONST_COLOR;
    710     case D3DBLEND_SRCCOLOR2:       return PIPE_BLENDFACTOR_SRC1_COLOR;
    711     case D3DBLEND_INVSRCCOLOR2:    return PIPE_BLENDFACTOR_INV_SRC1_COLOR;
    712     default:
    713        DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b);
    714        return PIPE_BLENDFACTOR_ZERO;
    715     }
    716 }
    717 
    718 static inline unsigned
    719 d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr)
    720 {
    721     switch (addr) {
    722     case D3DTADDRESS_WRAP:       return PIPE_TEX_WRAP_REPEAT;
    723     case D3DTADDRESS_MIRROR:     return PIPE_TEX_WRAP_MIRROR_REPEAT;
    724     case D3DTADDRESS_CLAMP:      return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    725     case D3DTADDRESS_BORDER:     return PIPE_TEX_WRAP_CLAMP_TO_BORDER;
    726     case D3DTADDRESS_MIRRORONCE: return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE;
    727     default:
    728         assert(0);
    729         return PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    730     }
    731 }
    732 
    733 static inline unsigned
    734 d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter)
    735 {
    736     switch (filter) {
    737     case D3DTEXF_POINT:       return PIPE_TEX_FILTER_NEAREST;
    738     case D3DTEXF_LINEAR:      return PIPE_TEX_FILTER_LINEAR;
    739     case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR;
    740 
    741     case D3DTEXF_NONE:
    742     case D3DTEXF_PYRAMIDALQUAD:
    743     case D3DTEXF_GAUSSIANQUAD:
    744     case D3DTEXF_CONVOLUTIONMONO:
    745     default:
    746         assert(0);
    747         return PIPE_TEX_FILTER_NEAREST;
    748     }
    749 }
    750 
    751 static inline unsigned
    752 d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter)
    753 {
    754     switch (filter) {
    755     case D3DTEXF_NONE:        return PIPE_TEX_MIPFILTER_NONE;
    756     case D3DTEXF_POINT:       return PIPE_TEX_FILTER_NEAREST;
    757     case D3DTEXF_LINEAR:      return PIPE_TEX_FILTER_LINEAR;
    758     case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR;
    759 
    760     case D3DTEXF_PYRAMIDALQUAD:
    761     case D3DTEXF_GAUSSIANQUAD:
    762     case D3DTEXF_CONVOLUTIONMONO:
    763     default:
    764         assert(0);
    765         return PIPE_TEX_MIPFILTER_NONE;
    766     }
    767 }
    768 
    769 static inline unsigned nine_format_get_stride(enum pipe_format format,
    770                                               unsigned width)
    771 {
    772     unsigned stride = util_format_get_stride(format, width);
    773 
    774     return align(stride, 4);
    775 }
    776 
    777 static inline unsigned nine_format_get_level_alloc_size(enum pipe_format format,
    778                                                         unsigned width,
    779                                                         unsigned height,
    780                                                         unsigned level)
    781 {
    782     unsigned w, h, size;
    783 
    784     w = u_minify(width, level);
    785     h = u_minify(height, level);
    786     if (is_ATI1_ATI2(format)) {
    787         /* For "unknown" formats like ATIx use width * height bytes */
    788         size = w * h;
    789     } else if (format == PIPE_FORMAT_NONE) { /* D3DFMT_NULL */
    790         size = w * h * 4;
    791     } else {
    792         size = nine_format_get_stride(format, w) *
    793             util_format_get_nblocksy(format, h);
    794     }
    795 
    796     return size;
    797 }
    798 
    799 static inline unsigned nine_format_get_size_and_offsets(enum pipe_format format,
    800                                                         unsigned *offsets,
    801                                                         unsigned width,
    802                                                         unsigned height,
    803                                                         unsigned last_level)
    804 {
    805     unsigned l, w, h, size = 0;
    806 
    807     for (l = 0; l <= last_level; ++l) {
    808         w = u_minify(width, l);
    809         h = u_minify(height, l);
    810         offsets[l] = size;
    811         if (is_ATI1_ATI2(format)) {
    812             /* For "unknown" formats like ATIx use width * height bytes */
    813             size += w * h;
    814         } else {
    815             size += nine_format_get_stride(format, w) *
    816                 util_format_get_nblocksy(format, h);
    817         }
    818     }
    819 
    820     return size;
    821 }
    822 
    823 #endif /* _NINE_PIPE_H_ */
    824