1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2014 VMware, Inc.
3bf215546Sopenharmony_ci * All Rights Reserved.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
7bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
8bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
9bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
10bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
11bf215546Sopenharmony_ci * the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
14bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
15bf215546Sopenharmony_ci * of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "u_inlines.h"
29bf215546Sopenharmony_ci#include "util/u_memory.h"
30bf215546Sopenharmony_ci#include "u_prim_restart.h"
31bf215546Sopenharmony_ci#include "u_prim.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_citypedef struct {
34bf215546Sopenharmony_ci  uint32_t count;
35bf215546Sopenharmony_ci  uint32_t primCount;
36bf215546Sopenharmony_ci  uint32_t firstIndex;
37bf215546Sopenharmony_ci  int32_t  baseVertex;
38bf215546Sopenharmony_ci  uint32_t reservedMustBeZero;
39bf215546Sopenharmony_ci} DrawElementsIndirectCommand;
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_cistatic DrawElementsIndirectCommand
42bf215546Sopenharmony_ciread_indirect_elements(struct pipe_context *context, const struct pipe_draw_indirect_info *indirect)
43bf215546Sopenharmony_ci{
44bf215546Sopenharmony_ci   DrawElementsIndirectCommand ret;
45bf215546Sopenharmony_ci   struct pipe_transfer *transfer = NULL;
46bf215546Sopenharmony_ci   void *map = NULL;
47bf215546Sopenharmony_ci   /* we only need the first 3 members */
48bf215546Sopenharmony_ci   unsigned read_size = 3 * sizeof(uint32_t);
49bf215546Sopenharmony_ci   assert(indirect->buffer->width0 > 3 * sizeof(uint32_t));
50bf215546Sopenharmony_ci   map = pipe_buffer_map_range(context, indirect->buffer,
51bf215546Sopenharmony_ci                                   indirect->offset,
52bf215546Sopenharmony_ci                                   read_size,
53bf215546Sopenharmony_ci                                   PIPE_MAP_READ,
54bf215546Sopenharmony_ci                                   &transfer);
55bf215546Sopenharmony_ci   assert(map);
56bf215546Sopenharmony_ci   memcpy(&ret, map, read_size);
57bf215546Sopenharmony_ci   pipe_buffer_unmap(context, transfer);
58bf215546Sopenharmony_ci   return ret;
59bf215546Sopenharmony_ci}
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_civoid
62bf215546Sopenharmony_ciutil_translate_prim_restart_data(unsigned index_size,
63bf215546Sopenharmony_ci                                 void *src_map, void *dst_map,
64bf215546Sopenharmony_ci                                 unsigned count, unsigned restart_index)
65bf215546Sopenharmony_ci{
66bf215546Sopenharmony_ci   if (index_size == 1) {
67bf215546Sopenharmony_ci      uint8_t *src = (uint8_t *) src_map;
68bf215546Sopenharmony_ci      uint16_t *dst = (uint16_t *) dst_map;
69bf215546Sopenharmony_ci      unsigned i;
70bf215546Sopenharmony_ci      for (i = 0; i < count; i++) {
71bf215546Sopenharmony_ci         dst[i] = (src[i] == restart_index) ? 0xffff : src[i];
72bf215546Sopenharmony_ci      }
73bf215546Sopenharmony_ci   }
74bf215546Sopenharmony_ci   else if (index_size == 2) {
75bf215546Sopenharmony_ci      uint16_t *src = (uint16_t *) src_map;
76bf215546Sopenharmony_ci      uint16_t *dst = (uint16_t *) dst_map;
77bf215546Sopenharmony_ci      unsigned i;
78bf215546Sopenharmony_ci      for (i = 0; i < count; i++) {
79bf215546Sopenharmony_ci         dst[i] = (src[i] == restart_index) ? 0xffff : src[i];
80bf215546Sopenharmony_ci      }
81bf215546Sopenharmony_ci   }
82bf215546Sopenharmony_ci   else {
83bf215546Sopenharmony_ci      uint32_t *src = (uint32_t *) src_map;
84bf215546Sopenharmony_ci      uint32_t *dst = (uint32_t *) dst_map;
85bf215546Sopenharmony_ci      unsigned i;
86bf215546Sopenharmony_ci      assert(index_size == 4);
87bf215546Sopenharmony_ci      for (i = 0; i < count; i++) {
88bf215546Sopenharmony_ci         dst[i] = (src[i] == restart_index) ? 0xffffffff : src[i];
89bf215546Sopenharmony_ci      }
90bf215546Sopenharmony_ci   }
91bf215546Sopenharmony_ci}
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci/**
94bf215546Sopenharmony_ci * Translate an index buffer for primitive restart.
95bf215546Sopenharmony_ci * Create a new index buffer which is a copy of the original index buffer
96bf215546Sopenharmony_ci * except that instances of 'restart_index' are converted to 0xffff or
97bf215546Sopenharmony_ci * 0xffffffff.
98bf215546Sopenharmony_ci * Also, index buffers using 1-byte indexes are converted to 2-byte indexes.
99bf215546Sopenharmony_ci */
100bf215546Sopenharmony_cienum pipe_error
101bf215546Sopenharmony_ciutil_translate_prim_restart_ib(struct pipe_context *context,
102bf215546Sopenharmony_ci                               const struct pipe_draw_info *info,
103bf215546Sopenharmony_ci                               const struct pipe_draw_indirect_info *indirect_info,
104bf215546Sopenharmony_ci                               const struct pipe_draw_start_count_bias *draw,
105bf215546Sopenharmony_ci                               struct pipe_resource **dst_buffer)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   struct pipe_screen *screen = context->screen;
108bf215546Sopenharmony_ci   struct pipe_transfer *src_transfer = NULL, *dst_transfer = NULL;
109bf215546Sopenharmony_ci   void *src_map = NULL, *dst_map = NULL;
110bf215546Sopenharmony_ci   const unsigned src_index_size = info->index_size;
111bf215546Sopenharmony_ci   unsigned dst_index_size;
112bf215546Sopenharmony_ci   DrawElementsIndirectCommand indirect;
113bf215546Sopenharmony_ci   unsigned count = draw->count;
114bf215546Sopenharmony_ci   unsigned start = draw->start;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   /* 1-byte indexes are converted to 2-byte indexes, 4-byte stays 4-byte */
117bf215546Sopenharmony_ci   dst_index_size = MAX2(2, info->index_size);
118bf215546Sopenharmony_ci   assert(dst_index_size == 2 || dst_index_size == 4);
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   if (indirect_info && indirect_info->buffer) {
121bf215546Sopenharmony_ci      indirect = read_indirect_elements(context, indirect_info);
122bf215546Sopenharmony_ci      count = indirect.count;
123bf215546Sopenharmony_ci      start = indirect.firstIndex;
124bf215546Sopenharmony_ci   }
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci   /* Create new index buffer */
127bf215546Sopenharmony_ci   *dst_buffer = pipe_buffer_create(screen, PIPE_BIND_INDEX_BUFFER,
128bf215546Sopenharmony_ci                                    PIPE_USAGE_STREAM,
129bf215546Sopenharmony_ci                                    count * dst_index_size);
130bf215546Sopenharmony_ci   if (!*dst_buffer)
131bf215546Sopenharmony_ci      goto error;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   /* Map new / dest index buffer */
134bf215546Sopenharmony_ci   dst_map = pipe_buffer_map(context, *dst_buffer,
135bf215546Sopenharmony_ci                             PIPE_MAP_WRITE, &dst_transfer);
136bf215546Sopenharmony_ci   if (!dst_map)
137bf215546Sopenharmony_ci      goto error;
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   if (info->has_user_indices)
140bf215546Sopenharmony_ci      src_map = (unsigned char*)info->index.user + start * src_index_size;
141bf215546Sopenharmony_ci   else
142bf215546Sopenharmony_ci      /* Map original / src index buffer */
143bf215546Sopenharmony_ci      src_map = pipe_buffer_map_range(context, info->index.resource,
144bf215546Sopenharmony_ci                                      start * src_index_size,
145bf215546Sopenharmony_ci                                      count * src_index_size,
146bf215546Sopenharmony_ci                                      PIPE_MAP_READ,
147bf215546Sopenharmony_ci                                      &src_transfer);
148bf215546Sopenharmony_ci   if (!src_map)
149bf215546Sopenharmony_ci      goto error;
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   util_translate_prim_restart_data(src_index_size, src_map, dst_map,
152bf215546Sopenharmony_ci                                    count, info->restart_index);
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   if (src_transfer)
155bf215546Sopenharmony_ci      pipe_buffer_unmap(context, src_transfer);
156bf215546Sopenharmony_ci   pipe_buffer_unmap(context, dst_transfer);
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   return PIPE_OK;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_cierror:
161bf215546Sopenharmony_ci   if (src_transfer)
162bf215546Sopenharmony_ci      pipe_buffer_unmap(context, src_transfer);
163bf215546Sopenharmony_ci   if (dst_transfer)
164bf215546Sopenharmony_ci      pipe_buffer_unmap(context, dst_transfer);
165bf215546Sopenharmony_ci   if (*dst_buffer)
166bf215546Sopenharmony_ci      pipe_resource_reference(dst_buffer, NULL);
167bf215546Sopenharmony_ci   return PIPE_ERROR_OUT_OF_MEMORY;
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci/** Helper structs for util_draw_vbo_without_prim_restart() */
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_cistruct range_info {
174bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias *draws;
175bf215546Sopenharmony_ci   unsigned count, max;
176bf215546Sopenharmony_ci   unsigned min_index, max_index;
177bf215546Sopenharmony_ci   unsigned total_index_count;
178bf215546Sopenharmony_ci};
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci/**
182bf215546Sopenharmony_ci * Helper function for util_draw_vbo_without_prim_restart()
183bf215546Sopenharmony_ci * \return true for success, false if out of memory
184bf215546Sopenharmony_ci */
185bf215546Sopenharmony_cistatic boolean
186bf215546Sopenharmony_ciadd_range(enum pipe_prim_type mode, struct range_info *info, unsigned start, unsigned count, unsigned index_bias)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   /* degenerate primitive: ignore */
189bf215546Sopenharmony_ci   if (!u_trim_pipe_prim(mode, (unsigned*)&count))
190bf215546Sopenharmony_ci      return TRUE;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   if (info->max == 0) {
193bf215546Sopenharmony_ci      info->max = 10;
194bf215546Sopenharmony_ci      info->draws = MALLOC(info->max * sizeof(struct pipe_draw_start_count_bias));
195bf215546Sopenharmony_ci      if (!info->draws) {
196bf215546Sopenharmony_ci         return FALSE;
197bf215546Sopenharmony_ci      }
198bf215546Sopenharmony_ci   }
199bf215546Sopenharmony_ci   else if (info->count == info->max) {
200bf215546Sopenharmony_ci      /* grow the draws[] array */
201bf215546Sopenharmony_ci      info->draws = REALLOC(info->draws,
202bf215546Sopenharmony_ci                             info->max * sizeof(struct pipe_draw_start_count_bias),
203bf215546Sopenharmony_ci                             2 * info->max * sizeof(struct pipe_draw_start_count_bias));
204bf215546Sopenharmony_ci      if (!info->draws) {
205bf215546Sopenharmony_ci         return FALSE;
206bf215546Sopenharmony_ci      }
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci      info->max *= 2;
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci   info->min_index = MIN2(info->min_index, start);
211bf215546Sopenharmony_ci   info->max_index = MAX2(info->max_index, start + count - 1);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   /* save the range */
214bf215546Sopenharmony_ci   info->draws[info->count].start = start;
215bf215546Sopenharmony_ci   info->draws[info->count].count = count;
216bf215546Sopenharmony_ci   info->draws[info->count].index_bias = index_bias;
217bf215546Sopenharmony_ci   info->count++;
218bf215546Sopenharmony_ci   info->total_index_count += count;
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   return TRUE;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistruct pipe_draw_start_count_bias *
224bf215546Sopenharmony_ciutil_prim_restart_convert_to_direct(const void *index_map,
225bf215546Sopenharmony_ci                                    const struct pipe_draw_info *info,
226bf215546Sopenharmony_ci                                    const struct pipe_draw_start_count_bias *draw,
227bf215546Sopenharmony_ci                                    unsigned *num_draws,
228bf215546Sopenharmony_ci                                    unsigned *min_index,
229bf215546Sopenharmony_ci                                    unsigned *max_index,
230bf215546Sopenharmony_ci                                    unsigned *total_index_count)
231bf215546Sopenharmony_ci{
232bf215546Sopenharmony_ci   struct range_info ranges = { .min_index = UINT32_MAX, 0 };
233bf215546Sopenharmony_ci   unsigned i, start, count;
234bf215546Sopenharmony_ci   ranges.min_index = UINT32_MAX;
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   assert(info->index_size);
237bf215546Sopenharmony_ci   assert(info->primitive_restart);
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci#define SCAN_INDEXES(TYPE) \
240bf215546Sopenharmony_ci   for (i = 0; i <= draw->count; i++) { \
241bf215546Sopenharmony_ci      if (i == draw->count || \
242bf215546Sopenharmony_ci          ((const TYPE *) index_map)[i] == info->restart_index) { \
243bf215546Sopenharmony_ci         /* cut / restart */ \
244bf215546Sopenharmony_ci         if (count > 0) { \
245bf215546Sopenharmony_ci            if (!add_range(info->mode, &ranges, draw->start + start, count, draw->index_bias)) { \
246bf215546Sopenharmony_ci               return NULL; \
247bf215546Sopenharmony_ci            } \
248bf215546Sopenharmony_ci         } \
249bf215546Sopenharmony_ci         start = i + 1; \
250bf215546Sopenharmony_ci         count = 0; \
251bf215546Sopenharmony_ci      } \
252bf215546Sopenharmony_ci      else { \
253bf215546Sopenharmony_ci         count++; \
254bf215546Sopenharmony_ci      } \
255bf215546Sopenharmony_ci   }
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   start = 0;
258bf215546Sopenharmony_ci   count = 0;
259bf215546Sopenharmony_ci   switch (info->index_size) {
260bf215546Sopenharmony_ci   case 1:
261bf215546Sopenharmony_ci      SCAN_INDEXES(uint8_t);
262bf215546Sopenharmony_ci      break;
263bf215546Sopenharmony_ci   case 2:
264bf215546Sopenharmony_ci      SCAN_INDEXES(uint16_t);
265bf215546Sopenharmony_ci      break;
266bf215546Sopenharmony_ci   case 4:
267bf215546Sopenharmony_ci      SCAN_INDEXES(uint32_t);
268bf215546Sopenharmony_ci      break;
269bf215546Sopenharmony_ci   default:
270bf215546Sopenharmony_ci      assert(!"Bad index size");
271bf215546Sopenharmony_ci      return NULL;
272bf215546Sopenharmony_ci   }
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   *num_draws = ranges.count;
275bf215546Sopenharmony_ci   *min_index = ranges.min_index;
276bf215546Sopenharmony_ci   *max_index = ranges.max_index;
277bf215546Sopenharmony_ci   *total_index_count = ranges.total_index_count;
278bf215546Sopenharmony_ci   return ranges.draws;
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci/**
282bf215546Sopenharmony_ci * Implement primitive restart by breaking an indexed primitive into
283bf215546Sopenharmony_ci * pieces which do not contain restart indexes.  Each piece is then
284bf215546Sopenharmony_ci * drawn by calling pipe_context::draw_vbo().
285bf215546Sopenharmony_ci * \return PIPE_OK if no error, an error code otherwise.
286bf215546Sopenharmony_ci */
287bf215546Sopenharmony_cienum pipe_error
288bf215546Sopenharmony_ciutil_draw_vbo_without_prim_restart(struct pipe_context *context,
289bf215546Sopenharmony_ci                                   const struct pipe_draw_info *info,
290bf215546Sopenharmony_ci                                   unsigned drawid_offset,
291bf215546Sopenharmony_ci                                   const struct pipe_draw_indirect_info *indirect_info,
292bf215546Sopenharmony_ci                                   const struct pipe_draw_start_count_bias *draw)
293bf215546Sopenharmony_ci{
294bf215546Sopenharmony_ci   const void *src_map;
295bf215546Sopenharmony_ci   struct pipe_draw_info new_info = *info;
296bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias new_draw = *draw;
297bf215546Sopenharmony_ci   struct pipe_transfer *src_transfer = NULL;
298bf215546Sopenharmony_ci   DrawElementsIndirectCommand indirect;
299bf215546Sopenharmony_ci   struct pipe_draw_start_count_bias *direct_draws;
300bf215546Sopenharmony_ci   unsigned num_draws = 0;
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci   assert(info->index_size);
303bf215546Sopenharmony_ci   assert(info->primitive_restart);
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   switch (info->index_size) {
306bf215546Sopenharmony_ci   case 1:
307bf215546Sopenharmony_ci   case 2:
308bf215546Sopenharmony_ci   case 4:
309bf215546Sopenharmony_ci      break;
310bf215546Sopenharmony_ci   default:
311bf215546Sopenharmony_ci      assert(!"Bad index size");
312bf215546Sopenharmony_ci      return PIPE_ERROR_BAD_INPUT;
313bf215546Sopenharmony_ci   }
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   if (indirect_info && indirect_info->buffer) {
316bf215546Sopenharmony_ci      indirect = read_indirect_elements(context, indirect_info);
317bf215546Sopenharmony_ci      new_draw.count = indirect.count;
318bf215546Sopenharmony_ci      new_draw.start = indirect.firstIndex;
319bf215546Sopenharmony_ci      new_info.instance_count = indirect.primCount;
320bf215546Sopenharmony_ci   }
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   /* Get pointer to the index data */
323bf215546Sopenharmony_ci   if (!info->has_user_indices) {
324bf215546Sopenharmony_ci      /* map the index buffer (only the range we need to scan) */
325bf215546Sopenharmony_ci      src_map = pipe_buffer_map_range(context, info->index.resource,
326bf215546Sopenharmony_ci                                      new_draw.start * info->index_size,
327bf215546Sopenharmony_ci                                      new_draw.count * info->index_size,
328bf215546Sopenharmony_ci                                      PIPE_MAP_READ,
329bf215546Sopenharmony_ci                                      &src_transfer);
330bf215546Sopenharmony_ci      if (!src_map) {
331bf215546Sopenharmony_ci         return PIPE_ERROR_OUT_OF_MEMORY;
332bf215546Sopenharmony_ci      }
333bf215546Sopenharmony_ci   }
334bf215546Sopenharmony_ci   else {
335bf215546Sopenharmony_ci      if (!info->index.user) {
336bf215546Sopenharmony_ci         debug_printf("User-space index buffer is null!");
337bf215546Sopenharmony_ci         return PIPE_ERROR_BAD_INPUT;
338bf215546Sopenharmony_ci      }
339bf215546Sopenharmony_ci      src_map = (const uint8_t *) info->index.user
340bf215546Sopenharmony_ci         + new_draw.start * info->index_size;
341bf215546Sopenharmony_ci   }
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci   unsigned total_index_count;
344bf215546Sopenharmony_ci   direct_draws = util_prim_restart_convert_to_direct(src_map, &new_info, &new_draw, &num_draws,
345bf215546Sopenharmony_ci                                                      &new_info.min_index, &new_info.max_index,
346bf215546Sopenharmony_ci                                                      &total_index_count);
347bf215546Sopenharmony_ci   /* unmap index buffer */
348bf215546Sopenharmony_ci   if (src_transfer)
349bf215546Sopenharmony_ci      pipe_buffer_unmap(context, src_transfer);
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   new_info.primitive_restart = FALSE;
352bf215546Sopenharmony_ci   new_info.index_bounds_valid = true;
353bf215546Sopenharmony_ci   if (direct_draws)
354bf215546Sopenharmony_ci      context->draw_vbo(context, &new_info, drawid_offset, NULL, direct_draws, num_draws);
355bf215546Sopenharmony_ci   free(direct_draws);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   return num_draws > 0 ? PIPE_OK : PIPE_ERROR_OUT_OF_MEMORY;
358bf215546Sopenharmony_ci}
359