#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 cso_context *, const DWORD *);
-void nine_convert_rasterizer_state(struct cso_context *, const DWORD *);
-void nine_convert_blend_state(struct cso_context *, const DWORD *);
+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 unsigned d3dlock_buffer_to_pipe_transfer_usage(DWORD Flags)
-{
- unsigned usage;
-
- if (Flags & D3DLOCK_DISCARD)
- usage = PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
- else
- if (Flags & D3DLOCK_READONLY)
- usage = PIPE_TRANSFER_READ;
- else
- usage = PIPE_TRANSFER_READ_WRITE;
-
- if (Flags & D3DLOCK_NOOVERWRITE)
- usage = (PIPE_TRANSFER_UNSYNCHRONIZED |
- PIPE_TRANSFER_DISCARD_RANGE | usage) & ~PIPE_TRANSFER_READ;
- else
- if (Flags & D3DLOCK_DONOTWAIT)
- usage |= PIPE_TRANSFER_DONTBLOCK;
-
- /*
- if (Flags & D3DLOCK_NO_DIRTY_UPDATE)
- usage |= PIPE_TRANSFER_FLUSH_EXPLICIT;
- */
-
- return usage;
-}
-
-static INLINE void
+static inline void
rect_to_pipe_box(struct pipe_box *dst, const RECT *src)
{
dst->x = src->left;
dst->depth = 1;
}
-static INLINE boolean
+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);
return FALSE;
}
-static INLINE boolean
+static inline boolean
rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *src)
{
rect_to_pipe_box(dst, src);
return TRUE;
}
-static INLINE void
-nine_u_rect_to_pipe_box(struct pipe_box *dst, const struct u_rect *rect, int z)
-{
- dst->x = rect->x0;
- dst->y = rect->y0;
- dst->z = z;
- dst->width = rect->x1 - rect->x0;
- dst->height = rect->y1 - rect->y0;
- dst->depth = 1;
-}
-
-static INLINE void
+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->height = src->bottom - src->top;
}
-static INLINE boolean
+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);
return FALSE;
}
-static INLINE void
+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->y1 = src->bottom;
}
-static INLINE void
+static inline void
d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src)
{
user_warn(src->Left > src->Right);
dst->depth = src->Back - src->Front;
}
-static INLINE D3DFORMAT
+static inline D3DFORMAT
pipe_to_d3d9_format(enum pipe_format format)
{
return nine_pipe_to_d3d9_format_map[format];
}
-static INLINE enum pipe_format
-d3d9_to_pipe_format(D3DFORMAT 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_Z24_UNORM_S8_UINT;
+ 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_Y210: /* XXX */
case D3DFMT_Y216:
case D3DFMT_NV11:
- case D3DFMT_DF16: /* useless, not supported by wine either */
- case D3DFMT_DF24: /* useless, not supported by wine either */
+ 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:
}
}
-static INLINE const char *
+#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_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_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
+static inline unsigned
nine_fvf_stride( DWORD fvf )
{
unsigned texcount, i, size = 0;
return size;
}
-static INLINE void
+static inline void
d3dcolor_to_rgba(float *rgba, D3DCOLOR color)
{
rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF;
rgba[3] = (float)((color >> 24) & 0xFF) / 0xFF;
}
-static INLINE void
+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
+static inline unsigned
d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim)
{
switch (prim) {
}
}
-static INLINE unsigned
+static inline unsigned
prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count)
{
switch (prim) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dcmpfunc_to_pipe_func(D3DCMPFUNC func)
{
switch (func) {
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
+static inline unsigned
d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op)
{
switch (op) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dcull_to_pipe_face(D3DCULL cull)
{
switch (cull) {
}
}
-static INLINE unsigned
+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
+static inline unsigned
d3dblendop_to_pipe_blend(D3DBLENDOP op)
{
switch (op) {
* Drivers may check RGB and ALPHA factors for equality so we should not
* simply substitute the ALPHA variants.
*/
-static INLINE unsigned
+static inline unsigned
d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b)
{
switch (b) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dblend_color_to_pipe_blendfactor(D3DBLEND b)
{
switch (b) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr)
{
switch (addr) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter)
{
switch (filter) {
}
}
-static INLINE unsigned
+static inline unsigned
d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter)
{
switch (filter) {
}
}
+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_ */