/* * Copyright 2011 Joakim Sindholt * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _NINE_PIPE_H_ #define _NINE_PIPE_H_ #include "d3d9.h" #include "pipe/p_format.h" #include "pipe/p_screen.h" #include "pipe/p_state.h" /* pipe_box */ #include "util/macros.h" #include "util/u_rect.h" #include "util/u_format.h" #include "nine_helpers.h" struct cso_context; extern const enum pipe_format nine_d3d9_to_pipe_format_map[120]; extern const D3DFORMAT nine_pipe_to_d3d9_format_map[PIPE_FORMAT_COUNT]; void nine_convert_dsa_state(struct pipe_depth_stencil_alpha_state *, const DWORD *); void nine_convert_rasterizer_state(struct NineDevice9 *, struct pipe_rasterizer_state *, const DWORD *); void nine_convert_blend_state(struct pipe_blend_state *, const DWORD *); void nine_convert_sampler_state(struct cso_context *, int idx, const DWORD *); void nine_pipe_context_clear(struct NineDevice9 *); #define is_ATI1_ATI2(format) (format == PIPE_FORMAT_RGTC1_UNORM || format == PIPE_FORMAT_RGTC2_UNORM) static inline void rect_to_pipe_box(struct pipe_box *dst, const RECT *src) { dst->x = src->left; dst->y = src->top; dst->z = 0; dst->width = src->right - src->left; dst->height = src->bottom - src->top; dst->depth = 1; } static inline void pipe_box_to_rect(RECT *dst, const struct pipe_box *src) { dst->left = src->x; dst->right = src->x + src->width; dst->top = src->y; dst->bottom = src->y + src->height; } static inline void rect_minify_inclusive(RECT *rect) { rect->left = rect->left >> 2; rect->top = rect->top >> 2; rect->right = DIV_ROUND_UP(rect->right, 2); rect->bottom = DIV_ROUND_UP(rect->bottom, 2); } /* We suppose: * 0 <= rect->left < rect->right * 0 <= rect->top < rect->bottom */ static inline void fit_rect_format_inclusive(enum pipe_format format, RECT *rect, int width, int height) { const unsigned w = util_format_get_blockwidth(format); const unsigned h = util_format_get_blockheight(format); if (util_format_is_compressed(format)) { rect->left = rect->left - rect->left % w; rect->top = rect->top - rect->top % h; rect->right = (rect->right % w) == 0 ? rect->right : rect->right - (rect->right % w) + w; rect->bottom = (rect->bottom % h) == 0 ? rect->bottom : rect->bottom - (rect->bottom % h) + h; } rect->right = MIN2(rect->right, width); rect->bottom = MIN2(rect->bottom, height); } static inline boolean rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *src) { rect_to_pipe_box(dst, src); if (dst->width <= 0 || dst->height <= 0) { DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box"); dst->width = MAX2(dst->width, 0); dst->height = MAX2(dst->height, 0); return TRUE; } return FALSE; } static inline boolean rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *src) { rect_to_pipe_box(dst, src); if (dst->width >= 0 && dst->height >= 0) return FALSE; if (dst->width < 0) dst->width = -dst->width; if (dst->height < 0) dst->height = -dst->height; return TRUE; } static inline void rect_to_pipe_box_xy_only(struct pipe_box *dst, const RECT *src) { user_warn(src->left > src->right || src->top > src->bottom); dst->x = src->left; dst->y = src->top; dst->width = src->right - src->left; dst->height = src->bottom - src->top; } static inline boolean rect_to_pipe_box_xy_only_clamp(struct pipe_box *dst, const RECT *src) { rect_to_pipe_box_xy_only(dst, src); if (dst->width <= 0 || dst->height <= 0) { DBG_FLAG(DBG_UNKNOWN, "Warning: NULL box"); dst->width = MAX2(dst->width, 0); dst->height = MAX2(dst->height, 0); return TRUE; } return FALSE; } static inline void rect_to_g3d_u_rect(struct u_rect *dst, const RECT *src) { user_warn(src->left > src->right || src->top > src->bottom); dst->x0 = src->left; dst->x1 = src->right; dst->y0 = src->top; dst->y1 = src->bottom; } static inline void d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src) { user_warn(src->Left > src->Right); user_warn(src->Top > src->Bottom); user_warn(src->Front > src->Back); dst->x = src->Left; dst->y = src->Top; dst->z = src->Front; dst->width = src->Right - src->Left; dst->height = src->Bottom - src->Top; dst->depth = src->Back - src->Front; } static inline D3DFORMAT pipe_to_d3d9_format(enum pipe_format format) { return nine_pipe_to_d3d9_format_map[format]; } /* ATI1 and ATI2 are not officially compressed in d3d9 */ static inline boolean compressed_format( D3DFORMAT fmt ) { switch (fmt) { case D3DFMT_DXT1: case D3DFMT_DXT2: case D3DFMT_DXT3: case D3DFMT_DXT4: case D3DFMT_DXT5: return TRUE; default: break; } return FALSE; } static inline boolean depth_stencil_format( D3DFORMAT fmt ) { static D3DFORMAT allowed[] = { D3DFMT_D16_LOCKABLE, D3DFMT_D32, D3DFMT_D15S1, D3DFMT_D24S8, D3DFMT_D24X8, D3DFMT_D24X4S4, D3DFMT_D16, D3DFMT_D32F_LOCKABLE, D3DFMT_D24FS8, D3DFMT_D32_LOCKABLE, D3DFMT_DF16, D3DFMT_DF24, D3DFMT_INTZ }; unsigned i; for (i = 0; i < sizeof(allowed)/sizeof(D3DFORMAT); i++) { if (fmt == allowed[i]) { return TRUE; } } return FALSE; } static inline unsigned d3d9_get_pipe_depth_format_bindings(D3DFORMAT format) { switch (format) { case D3DFMT_D32: case D3DFMT_D15S1: case D3DFMT_D24S8: case D3DFMT_D24X8: case D3DFMT_D24X4S4: case D3DFMT_D16: case D3DFMT_D24FS8: return PIPE_BIND_DEPTH_STENCIL; case D3DFMT_D32F_LOCKABLE: case D3DFMT_D16_LOCKABLE: case D3DFMT_D32_LOCKABLE: return PIPE_BIND_DEPTH_STENCIL; case D3DFMT_DF16: case D3DFMT_DF24: case D3DFMT_INTZ: return PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_SAMPLER_VIEW; default: unreachable("Unexpected format"); } } static inline enum pipe_format d3d9_to_pipe_format_internal(D3DFORMAT format) { if (format <= D3DFMT_A2B10G10R10_XR_BIAS) return nine_d3d9_to_pipe_format_map[format]; switch (format) { case D3DFMT_INTZ: return PIPE_FORMAT_S8_UINT_Z24_UNORM; case D3DFMT_DF16: return PIPE_FORMAT_Z16_UNORM; case D3DFMT_DXT1: return PIPE_FORMAT_DXT1_RGBA; case D3DFMT_DXT2: return PIPE_FORMAT_DXT3_RGBA; /* XXX */ case D3DFMT_DXT3: return PIPE_FORMAT_DXT3_RGBA; case D3DFMT_DXT4: return PIPE_FORMAT_DXT5_RGBA; /* XXX */ case D3DFMT_DXT5: return PIPE_FORMAT_DXT5_RGBA; case D3DFMT_ATI1: return PIPE_FORMAT_RGTC1_UNORM; case D3DFMT_ATI2: return PIPE_FORMAT_RGTC2_UNORM; case D3DFMT_UYVY: return PIPE_FORMAT_UYVY; case D3DFMT_YUY2: return PIPE_FORMAT_YUYV; /* XXX check */ case D3DFMT_NV12: return PIPE_FORMAT_NV12; case D3DFMT_G8R8_G8B8: return PIPE_FORMAT_G8R8_G8B8_UNORM; /* XXX order ? */ case D3DFMT_R8G8_B8G8: return PIPE_FORMAT_R8G8_B8G8_UNORM; /* XXX order ? */ case D3DFMT_BINARYBUFFER: return PIPE_FORMAT_NONE; /* not a format */ case D3DFMT_MULTI2_ARGB8: return PIPE_FORMAT_NONE; /* not supported */ case D3DFMT_Y210: /* XXX */ case D3DFMT_Y216: case D3DFMT_NV11: case D3DFMT_DF24: /* Similar to D3DFMT_DF16 but for 24-bits. We don't advertise it because when it is supported, Fetch-4 is supposed to be supported, which we don't support yet. */ case D3DFMT_NULL: /* special cased, only for surfaces */ return PIPE_FORMAT_NONE; default: DBG_FLAG(DBG_UNKNOWN, "unknown D3DFORMAT: 0x%x/%c%c%c%c\n", format, (char)format, (char)(format >> 8), (char)(format >> 16), (char)(format >> 24)); return PIPE_FORMAT_NONE; } } #define format_check_internal(pipe_format) \ screen->is_format_supported(screen, pipe_format, target, \ sample_count, bindings) static inline enum pipe_format d3d9_to_pipe_format_checked(struct pipe_screen *screen, D3DFORMAT format, enum pipe_texture_target target, unsigned sample_count, unsigned bindings, boolean srgb, boolean bypass_check) { enum pipe_format result; result = d3d9_to_pipe_format_internal(format); if (result == PIPE_FORMAT_NONE) return PIPE_FORMAT_NONE; if (srgb) result = util_format_srgb(result); /* bypass_check: Used for D3DPOOL_SCRATCH, which * isn't limited to the formats supported by the * device, and to check we are not using a format * fallback. */ if (bypass_check || format_check_internal(result)) return result; /* fallback to another format for formats * that match several pipe_format */ switch(format) { /* depth buffer formats are not lockable (except those for which it * is precised in the name), so it is ok to match to another similar * format. In all cases, if the app reads the texture with a shader, * it gets depth on r and doesn't get stencil.*/ case D3DFMT_INTZ: case D3DFMT_D24S8: if (format_check_internal(PIPE_FORMAT_Z24_UNORM_S8_UINT)) return PIPE_FORMAT_Z24_UNORM_S8_UINT; break; case D3DFMT_D24X8: if (format_check_internal(PIPE_FORMAT_Z24X8_UNORM)) return PIPE_FORMAT_Z24X8_UNORM; break; /* Support for X8L8V8U8 bumpenvmap format with lighting bits. * X8L8V8U8 is commonly supported among dx9 cards. * To avoid precision loss, we use PIPE_FORMAT_R32G32B32X32_FLOAT, * however using PIPE_FORMAT_R8G8B8A8_SNORM should be ok */ case D3DFMT_X8L8V8U8: if (bindings & PIPE_BIND_RENDER_TARGET) return PIPE_FORMAT_NONE; if (format_check_internal(PIPE_FORMAT_R32G32B32X32_FLOAT)) return PIPE_FORMAT_R32G32B32X32_FLOAT; default: break; } return PIPE_FORMAT_NONE; } /* The quality levels are vendor dependent, so we set our own. * Every quality level has its own sample count and sample * position matrix. * The exact mapping might differ from system to system but thats OK, * as there's no way to gather more information about quality levels * in D3D9. * In case of NONMASKABLE multisample map every quality-level * to a MASKABLE MultiSampleType: * 0: no MSAA * 1: 2x MSAA * 2: 4x MSAA * ... * If the requested quality level is not available to nearest * matching quality level is used. * If no multisample is available the function sets * multisample to D3DMULTISAMPLE_NONE and returns zero. */ static inline HRESULT d3dmultisample_type_check(struct pipe_screen *screen, D3DFORMAT format, D3DMULTISAMPLE_TYPE *multisample, DWORD multisamplequality, DWORD *levels) { unsigned bind, i; assert(multisample); if (levels) *levels = 1; if (*multisample == D3DMULTISAMPLE_NONMASKABLE) { if (depth_stencil_format(format)) bind = d3d9_get_pipe_depth_format_bindings(format); else /* render-target */ bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; *multisample = 0; for (i = D3DMULTISAMPLE_2_SAMPLES; i < D3DMULTISAMPLE_16_SAMPLES && multisamplequality; ++i) { if (d3d9_to_pipe_format_checked(screen, format, PIPE_TEXTURE_2D, i, bind, FALSE, FALSE) != PIPE_FORMAT_NONE) { multisamplequality--; if (levels) (*levels)++; *multisample = i; } } } /* Make sure to get an exact match */ if (multisamplequality) return D3DERR_INVALIDCALL; return D3D_OK; } static inline const char * d3dformat_to_string(D3DFORMAT fmt) { switch (fmt) { case D3DFMT_UNKNOWN: return "D3DFMT_UNKNOWN"; case D3DFMT_R8G8B8: return "D3DFMT_R8G8B8"; case D3DFMT_A8R8G8B8: return "D3DFMT_A8R8G8B8"; case D3DFMT_X8R8G8B8: return "D3DFMT_X8R8G8B8"; case D3DFMT_R5G6B5: return "D3DFMT_R5G6B5"; case D3DFMT_X1R5G5B5: return "D3DFMT_X1R5G5B5"; case D3DFMT_A1R5G5B5: return "D3DFMT_A1R5G5B5"; case D3DFMT_A4R4G4B4: return "D3DFMT_A4R4G4B4"; case D3DFMT_R3G3B2: return "D3DFMT_R3G3B2"; case D3DFMT_A8: return "D3DFMT_A8"; case D3DFMT_A8R3G3B2: return "D3DFMT_A8R3G3B2"; case D3DFMT_X4R4G4B4: return "D3DFMT_X4R4G4B4"; case D3DFMT_A2B10G10R10: return "D3DFMT_A2B10G10R10"; case D3DFMT_A8B8G8R8: return "D3DFMT_A8B8G8R8"; case D3DFMT_X8B8G8R8: return "D3DFMT_X8B8G8R8"; case D3DFMT_G16R16: return "D3DFMT_G16R16"; case D3DFMT_A2R10G10B10: return "D3DFMT_A2R10G10B10"; case D3DFMT_A16B16G16R16: return "D3DFMT_A16B16G16R16"; case D3DFMT_A8P8: return "D3DFMT_A8P8"; case D3DFMT_P8: return "D3DFMT_P8"; case D3DFMT_L8: return "D3DFMT_L8"; case D3DFMT_A8L8: return "D3DFMT_A8L8"; case D3DFMT_A4L4: return "D3DFMT_A4L4"; case D3DFMT_V8U8: return "D3DFMT_V8U8"; case D3DFMT_L6V5U5: return "D3DFMT_L6V5U5"; case D3DFMT_X8L8V8U8: return "D3DFMT_X8L8V8U8"; case D3DFMT_Q8W8V8U8: return "D3DFMT_Q8W8V8U8"; case D3DFMT_V16U16: return "D3DFMT_V16U16"; case D3DFMT_A2W10V10U10: return "D3DFMT_A2W10V10U10"; case D3DFMT_UYVY: return "D3DFMT_UYVY"; case D3DFMT_R8G8_B8G8: return "D3DFMT_R8G8_B8G8"; case D3DFMT_YUY2: return "D3DFMT_YUY2"; case D3DFMT_G8R8_G8B8: return "D3DFMT_G8R8_G8B8"; case D3DFMT_DXT1: return "D3DFMT_DXT1"; case D3DFMT_DXT2: return "D3DFMT_DXT2"; case D3DFMT_DXT3: return "D3DFMT_DXT3"; case D3DFMT_DXT4: return "D3DFMT_DXT4"; case D3DFMT_DXT5: return "D3DFMT_DXT5"; case D3DFMT_ATI1: return "D3DFMT_ATI1"; case D3DFMT_ATI2: return "D3DFMT_ATI2"; case D3DFMT_D16_LOCKABLE: return "D3DFMT_D16_LOCKABLE"; case D3DFMT_D32: return "D3DFMT_D32"; case D3DFMT_D15S1: return "D3DFMT_D15S1"; case D3DFMT_D24S8: return "D3DFMT_D24S8"; case D3DFMT_D24X8: return "D3DFMT_D24X8"; case D3DFMT_D24X4S4: return "D3DFMT_D24X4S4"; case D3DFMT_D16: return "D3DFMT_D16"; case D3DFMT_D32F_LOCKABLE: return "D3DFMT_D32F_LOCKABLE"; case D3DFMT_D24FS8: return "D3DFMT_D24FS8"; case D3DFMT_D32_LOCKABLE: return "D3DFMT_D32_LOCKABLE"; case D3DFMT_S8_LOCKABLE: return "D3DFMT_S8_LOCKABLE"; case D3DFMT_L16: return "D3DFMT_L16"; case D3DFMT_VERTEXDATA: return "D3DFMT_VERTEXDATA"; case D3DFMT_INDEX16: return "D3DFMT_INDEX16"; case D3DFMT_INDEX32: return "D3DFMT_INDEX32"; case D3DFMT_Q16W16V16U16: return "D3DFMT_Q16W16V16U16"; case D3DFMT_MULTI2_ARGB8: return "D3DFMT_MULTI2_ARGB8"; case D3DFMT_R16F: return "D3DFMT_R16F"; case D3DFMT_G16R16F: return "D3DFMT_G16R16F"; case D3DFMT_A16B16G16R16F: return "D3DFMT_A16B16G16R16F"; case D3DFMT_R32F: return "D3DFMT_R32F"; case D3DFMT_G32R32F: return "D3DFMT_G32R32F"; case D3DFMT_A32B32G32R32F: return "D3DFMT_A32B32G32R32F"; case D3DFMT_CxV8U8: return "D3DFMT_CxV8U8"; case D3DFMT_A1: return "D3DFMT_A1"; case D3DFMT_A2B10G10R10_XR_BIAS: return "D3DFMT_A2B10G10R10_XR_BIAS"; case D3DFMT_BINARYBUFFER: return "D3DFMT_BINARYBUFFER"; case D3DFMT_DF16: return "D3DFMT_DF16"; case D3DFMT_DF24: return "D3DFMT_DF24"; case D3DFMT_INTZ: return "D3DFMT_INTZ"; case D3DFMT_NVDB: return "D3DFMT_NVDB"; case D3DFMT_RESZ: return "D3DFMT_RESZ"; case D3DFMT_NULL: return "D3DFMT_NULL"; case D3DFMT_ATOC: return "D3DFMT_ATOC"; default: break; } return "Unknown"; } static inline unsigned nine_fvf_stride( DWORD fvf ) { unsigned texcount, i, size = 0; switch (fvf & D3DFVF_POSITION_MASK) { case D3DFVF_XYZ: size += 3*4; break; case D3DFVF_XYZRHW: size += 4*4; break; case D3DFVF_XYZB1: size += 4*4; break; case D3DFVF_XYZB2: size += 5*4; break; case D3DFVF_XYZB3: size += 6*4; break; case D3DFVF_XYZB4: size += 7*4; break; case D3DFVF_XYZB5: size += 8*4; break; case D3DFVF_XYZW: size += 4*4; break; default: user_warn("Position doesn't match any known combination."); break; } if (fvf & D3DFVF_NORMAL) { size += 3*4; } if (fvf & D3DFVF_PSIZE) { size += 1*4; } if (fvf & D3DFVF_DIFFUSE) { size += 1*4; } if (fvf & D3DFVF_SPECULAR) { size += 1*4; } texcount = (fvf >> D3DFVF_TEXCOUNT_SHIFT) & D3DFVF_TEXCOUNT_MASK; if (user_error(texcount <= 8)) texcount = 8; for (i = 0; i < texcount; ++i) { unsigned texformat = (fvf>>(16+i*2))&0x3; /* texformats are defined having been shifted around so 1=3,2=0,3=1,4=2 * meaning we can just do this instead of the switch below */ size += (((texformat+1)&0x3)+1)*4; /* switch (texformat) { case D3DFVF_TEXTUREFORMAT1: size += 1*4; case D3DFVF_TEXTUREFORMAT2: size += 2*4; case D3DFVF_TEXTUREFORMAT3: size += 3*4; case D3DFVF_TEXTUREFORMAT4: size += 4*4; } */ } return size; } static inline void d3dcolor_to_rgba(float *rgba, D3DCOLOR color) { rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF; rgba[1] = (float)((color >> 8) & 0xFF) / 0xFF; rgba[2] = (float)((color >> 0) & 0xFF) / 0xFF; rgba[3] = (float)((color >> 24) & 0xFF) / 0xFF; } static inline void d3dcolor_to_pipe_color_union(union pipe_color_union *rgba, D3DCOLOR color) { d3dcolor_to_rgba(&rgba->f[0], color); } static inline unsigned d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim) { switch (prim) { case D3DPT_POINTLIST: return PIPE_PRIM_POINTS; case D3DPT_LINELIST: return PIPE_PRIM_LINES; case D3DPT_LINESTRIP: return PIPE_PRIM_LINE_STRIP; case D3DPT_TRIANGLELIST: return PIPE_PRIM_TRIANGLES; case D3DPT_TRIANGLESTRIP: return PIPE_PRIM_TRIANGLE_STRIP; case D3DPT_TRIANGLEFAN: return PIPE_PRIM_TRIANGLE_FAN; default: assert(0); return PIPE_PRIM_POINTS; } } static inline unsigned prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count) { switch (prim) { case D3DPT_POINTLIST: return count; case D3DPT_LINELIST: return count * 2; case D3DPT_LINESTRIP: return count + 1; case D3DPT_TRIANGLELIST: return count * 3; case D3DPT_TRIANGLESTRIP: return count + 2; case D3DPT_TRIANGLEFAN: return count + 2; default: assert(0); return 0; } } static inline unsigned d3dcmpfunc_to_pipe_func(D3DCMPFUNC func) { switch (func) { case D3DCMP_NEVER: return PIPE_FUNC_NEVER; case D3DCMP_LESS: return PIPE_FUNC_LESS; case D3DCMP_EQUAL: return PIPE_FUNC_EQUAL; case D3DCMP_LESSEQUAL: return PIPE_FUNC_LEQUAL; case D3DCMP_GREATER: return PIPE_FUNC_GREATER; case D3DCMP_NOTEQUAL: return PIPE_FUNC_NOTEQUAL; case D3DCMP_GREATEREQUAL: return PIPE_FUNC_GEQUAL; case D3DCMP_ALWAYS: return PIPE_FUNC_ALWAYS; case D3DCMP_NEVER_ZERO: return PIPE_FUNC_NEVER; // Tested on windows + ATI HD5770 default: assert(0); return PIPE_FUNC_NEVER; } } static inline unsigned d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op) { switch (op) { case D3DSTENCILOP_KEEP: return PIPE_STENCIL_OP_KEEP; case D3DSTENCILOP_ZERO: return PIPE_STENCIL_OP_ZERO; case D3DSTENCILOP_REPLACE: return PIPE_STENCIL_OP_REPLACE; case D3DSTENCILOP_INCRSAT: return PIPE_STENCIL_OP_INCR; case D3DSTENCILOP_DECRSAT: return PIPE_STENCIL_OP_DECR; case D3DSTENCILOP_INVERT: return PIPE_STENCIL_OP_INVERT; case D3DSTENCILOP_INCR: return PIPE_STENCIL_OP_INCR_WRAP; case D3DSTENCILOP_DECR: return PIPE_STENCIL_OP_DECR_WRAP; default: return PIPE_STENCIL_OP_ZERO; } } static inline unsigned d3dcull_to_pipe_face(D3DCULL cull) { switch (cull) { case D3DCULL_NONE: return PIPE_FACE_NONE; case D3DCULL_CW: return PIPE_FACE_FRONT; case D3DCULL_CCW: return PIPE_FACE_BACK; default: assert(0); return PIPE_FACE_NONE; } } static inline unsigned d3dfillmode_to_pipe_polygon_mode(D3DFILLMODE mode) { switch (mode) { case D3DFILL_POINT: return PIPE_POLYGON_MODE_POINT; case D3DFILL_WIREFRAME: return PIPE_POLYGON_MODE_LINE; case D3DFILL_SOLID: return PIPE_POLYGON_MODE_FILL; case D3DFILL_SOLID_ZERO:return PIPE_POLYGON_MODE_FILL; default: assert(0); return PIPE_POLYGON_MODE_FILL; } } static inline unsigned d3dblendop_to_pipe_blend(D3DBLENDOP op) { switch (op) { case D3DBLENDOP_ADD: return PIPE_BLEND_ADD; case D3DBLENDOP_SUBTRACT: return PIPE_BLEND_SUBTRACT; case D3DBLENDOP_REVSUBTRACT: return PIPE_BLEND_REVERSE_SUBTRACT; case D3DBLENDOP_MIN: return PIPE_BLEND_MIN; case D3DBLENDOP_MAX: return PIPE_BLEND_MAX; default: assert(0); return PIPE_BLEND_ADD; } } /* NOTE: The COLOR factors for are equal to the ALPHA ones for alpha. * Drivers may check RGB and ALPHA factors for equality so we should not * simply substitute the ALPHA variants. */ static inline unsigned d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b) { switch (b) { case D3DBLEND_ZERO: return PIPE_BLENDFACTOR_ZERO; case D3DBLEND_ONE: return PIPE_BLENDFACTOR_ONE; case D3DBLEND_SRCCOLOR: return PIPE_BLENDFACTOR_SRC_COLOR/*ALPHA*/; case D3DBLEND_INVSRCCOLOR: return PIPE_BLENDFACTOR_INV_SRC_COLOR/*ALPHA*/; case D3DBLEND_SRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; case D3DBLEND_INVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; case D3DBLEND_DESTALPHA: return PIPE_BLENDFACTOR_DST_ALPHA; case D3DBLEND_INVDESTALPHA: return PIPE_BLENDFACTOR_INV_DST_ALPHA; case D3DBLEND_DESTCOLOR: return PIPE_BLENDFACTOR_DST_COLOR/*ALPHA*/; case D3DBLEND_INVDESTCOLOR: return PIPE_BLENDFACTOR_INV_DST_COLOR/*ALPHA*/; case D3DBLEND_SRCALPHASAT: return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; case D3DBLEND_BOTHSRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; case D3DBLEND_BLENDFACTOR: return PIPE_BLENDFACTOR_CONST_COLOR/*ALPHA*/; case D3DBLEND_INVBLENDFACTOR: return PIPE_BLENDFACTOR_INV_CONST_COLOR/*ALPHA*/; case D3DBLEND_SRCCOLOR2: return PIPE_BLENDFACTOR_ONE; /* XXX */ case D3DBLEND_INVSRCCOLOR2: return PIPE_BLENDFACTOR_ZERO; /* XXX */ default: DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b); return PIPE_BLENDFACTOR_ZERO; } } static inline unsigned d3dblend_color_to_pipe_blendfactor(D3DBLEND b) { switch (b) { case D3DBLEND_ZERO: return PIPE_BLENDFACTOR_ZERO; case D3DBLEND_ONE: return PIPE_BLENDFACTOR_ONE; case D3DBLEND_SRCCOLOR: return PIPE_BLENDFACTOR_SRC_COLOR; case D3DBLEND_INVSRCCOLOR: return PIPE_BLENDFACTOR_INV_SRC_COLOR; case D3DBLEND_SRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; case D3DBLEND_INVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; case D3DBLEND_DESTALPHA: return PIPE_BLENDFACTOR_DST_ALPHA; case D3DBLEND_INVDESTALPHA: return PIPE_BLENDFACTOR_INV_DST_ALPHA; case D3DBLEND_DESTCOLOR: return PIPE_BLENDFACTOR_DST_COLOR; case D3DBLEND_INVDESTCOLOR: return PIPE_BLENDFACTOR_INV_DST_COLOR; case D3DBLEND_SRCALPHASAT: return PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE; case D3DBLEND_BOTHSRCALPHA: return PIPE_BLENDFACTOR_SRC_ALPHA; case D3DBLEND_BOTHINVSRCALPHA: return PIPE_BLENDFACTOR_INV_SRC_ALPHA; case D3DBLEND_BLENDFACTOR: return PIPE_BLENDFACTOR_CONST_COLOR; case D3DBLEND_INVBLENDFACTOR: return PIPE_BLENDFACTOR_INV_CONST_COLOR; case D3DBLEND_SRCCOLOR2: return PIPE_BLENDFACTOR_SRC1_COLOR; case D3DBLEND_INVSRCCOLOR2: return PIPE_BLENDFACTOR_INV_SRC1_COLOR; default: DBG_FLAG(DBG_UNKNOWN, "Unhandled blend factor %d\n", b); return PIPE_BLENDFACTOR_ZERO; } } static inline unsigned d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr) { switch (addr) { case D3DTADDRESS_WRAP: return PIPE_TEX_WRAP_REPEAT; case D3DTADDRESS_MIRROR: return PIPE_TEX_WRAP_MIRROR_REPEAT; case D3DTADDRESS_CLAMP: return PIPE_TEX_WRAP_CLAMP_TO_EDGE; case D3DTADDRESS_BORDER: return PIPE_TEX_WRAP_CLAMP_TO_BORDER; case D3DTADDRESS_MIRRORONCE: return PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE; default: assert(0); return PIPE_TEX_WRAP_CLAMP_TO_EDGE; } } static inline unsigned d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter) { switch (filter) { case D3DTEXF_POINT: return PIPE_TEX_FILTER_NEAREST; case D3DTEXF_LINEAR: return PIPE_TEX_FILTER_LINEAR; case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR; case D3DTEXF_NONE: case D3DTEXF_PYRAMIDALQUAD: case D3DTEXF_GAUSSIANQUAD: case D3DTEXF_CONVOLUTIONMONO: default: assert(0); return PIPE_TEX_FILTER_NEAREST; } } static inline unsigned d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter) { switch (filter) { case D3DTEXF_NONE: return PIPE_TEX_MIPFILTER_NONE; case D3DTEXF_POINT: return PIPE_TEX_FILTER_NEAREST; case D3DTEXF_LINEAR: return PIPE_TEX_FILTER_LINEAR; case D3DTEXF_ANISOTROPIC: return PIPE_TEX_FILTER_LINEAR; case D3DTEXF_PYRAMIDALQUAD: case D3DTEXF_GAUSSIANQUAD: case D3DTEXF_CONVOLUTIONMONO: default: assert(0); return PIPE_TEX_MIPFILTER_NONE; } } static inline unsigned nine_format_get_stride(enum pipe_format format, unsigned width) { unsigned stride = util_format_get_stride(format, width); return align(stride, 4); } static inline unsigned nine_format_get_level_alloc_size(enum pipe_format format, unsigned width, unsigned height, unsigned level) { unsigned w, h, size; w = u_minify(width, level); h = u_minify(height, level); if (is_ATI1_ATI2(format)) { /* For "unknown" formats like ATIx use width * height bytes */ size = w * h; } else if (format == PIPE_FORMAT_NONE) { /* D3DFMT_NULL */ size = w * h * 4; } else { size = nine_format_get_stride(format, w) * util_format_get_nblocksy(format, h); } return size; } static inline unsigned nine_format_get_size_and_offsets(enum pipe_format format, unsigned *offsets, unsigned width, unsigned height, unsigned last_level) { unsigned l, w, h, size = 0; for (l = 0; l <= last_level; ++l) { w = u_minify(width, l); h = u_minify(height, l); offsets[l] = size; if (is_ATI1_ATI2(format)) { /* For "unknown" formats like ATIx use width * height bytes */ size += w * h; } else { size += nine_format_get_stride(format, w) * util_format_get_nblocksy(format, h); } } return size; } #endif /* _NINE_PIPE_H_ */