st/nine: Integrate nine_pipe_context_clear to nine_context_clear
[mesa.git] / src / gallium / state_trackers / nine / nine_pipe.h
index 1fd16944fd5e3bed3f3b9260131d22dd5bde4be0..6bd4a0c89720026cc5911358e378631743b1341f 100644 (file)
 
 #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;
@@ -34,41 +37,14 @@ 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;
@@ -79,7 +55,50 @@ rect_to_pipe_box(struct pipe_box *dst, const RECT *src)
     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);
@@ -93,7 +112,7 @@ rect_to_pipe_box_clamp(struct pipe_box *dst, const RECT *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);
@@ -105,18 +124,7 @@ rect_to_pipe_box_flip(struct pipe_box *dst, const RECT *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);
@@ -127,7 +135,7 @@ rect_to_pipe_box_xy_only(struct pipe_box *dst, const RECT *src)
     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);
@@ -141,7 +149,7 @@ rect_to_pipe_box_xy_only_clamp(struct pipe_box *dst, const RECT *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);
@@ -152,7 +160,7 @@ rect_to_g3d_u_rect(struct u_rect *dst, const RECT *src)
     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);
@@ -167,24 +175,94 @@ d3dbox_to_pipe_box(struct pipe_box *dst, const D3DBOX *src)
     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;
@@ -195,8 +273,9 @@ d3d9_to_pipe_format(D3DFORMAT format)
     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:
@@ -207,7 +286,122 @@ d3d9_to_pipe_format(D3DFORMAT format)
     }
 }
 
-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) {
@@ -249,6 +443,8 @@ d3dformat_to_string(D3DFORMAT 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";
@@ -279,14 +475,17 @@ d3dformat_to_string(D3DFORMAT fmt)
     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;
@@ -333,7 +532,7 @@ nine_fvf_stride( DWORD fvf )
     return size;
 }
 
-static INLINE void
+static inline void
 d3dcolor_to_rgba(float *rgba, D3DCOLOR color)
 {
     rgba[0] = (float)((color >> 16) & 0xFF) / 0xFF;
@@ -342,13 +541,13 @@ d3dcolor_to_rgba(float *rgba, D3DCOLOR color)
     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) {
@@ -364,7 +563,7 @@ d3dprimitivetype_to_pipe_prim(D3DPRIMITIVETYPE prim)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count)
 {
     switch (prim) {
@@ -380,7 +579,7 @@ prim_count_to_vertex_count(D3DPRIMITIVETYPE prim, UINT count)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dcmpfunc_to_pipe_func(D3DCMPFUNC func)
 {
     switch (func) {
@@ -392,13 +591,14 @@ d3dcmpfunc_to_pipe_func(D3DCMPFUNC 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) {
@@ -415,7 +615,7 @@ d3dstencilop_to_pipe_stencil_op(D3DSTENCILOP op)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dcull_to_pipe_face(D3DCULL cull)
 {
     switch (cull) {
@@ -428,20 +628,21 @@ d3dcull_to_pipe_face(D3DCULL 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) {
@@ -460,7 +661,7 @@ d3dblendop_to_pipe_blend(D3DBLENDOP 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) {
@@ -487,7 +688,7 @@ d3dblend_alpha_to_pipe_blendfactor(D3DBLEND b)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dblend_color_to_pipe_blendfactor(D3DBLEND b)
 {
     switch (b) {
@@ -514,7 +715,7 @@ d3dblend_color_to_pipe_blendfactor(D3DBLEND b)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr)
 {
     switch (addr) {
@@ -529,7 +730,7 @@ d3dtextureaddress_to_pipe_tex_wrap(D3DTEXTUREADDRESS addr)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter)
 {
     switch (filter) {
@@ -547,7 +748,7 @@ d3dtexturefiltertype_to_pipe_tex_filter(D3DTEXTUREFILTERTYPE filter)
     }
 }
 
-static INLINE unsigned
+static inline unsigned
 d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE filter)
 {
     switch (filter) {
@@ -565,4 +766,58 @@ d3dtexturefiltertype_to_pipe_tex_mipfilter(D3DTEXTUREFILTERTYPE 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_ */