1/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
2*
3* Redistribution and use in source and binary forms, with or without
4* modification, are permitted provided that the following conditions are
5* met:
6*  * Redistributions of source code must retain the above copyright
7*    notice, this list of conditions and the following disclaimer.
8*  * Redistributions in binary form must reproduce the above
9*    copyright notice, this list of conditions and the following
10*    disclaimer in the documentation and/or other materials provided
11*    with the distribution.
12*  * Neither the name of The Linux Foundation nor the names of its
13*    contributors may be used to endorse or promote products derived
14*    from this software without specific prior written permission.
15*
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29* Portions formerly licensed under Apache License, Version 2.0, are re licensed
30* under section 4 of Apache License, Version 2.0.
31
32* Copyright (C) 2010 The Android Open Source Project
33
34* Not a Contribution.
35
36* Licensed under the Apache License, Version 2.0 (the "License");
37* you may not use this file except in compliance with the License.
38* You may obtain a copy of the License at
39
40* http://www.apache.org/licenses/LICENSE-2.0
41
42* Unless required by applicable law or agreed to in writing, software
43* distributed under the License is distributed on an "AS IS" BASIS,
44* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45* See the License for the specific language governing permissions and
46* limitations under the License.
47*/
48
49#include <hardware/hardware.h>
50#include <sync/sync.h>
51#include <copybit.h>
52#include <memalloc.h>
53#include <alloc_controller.h>
54#include <gr.h>
55
56#include <utils/constants.h>
57#include <utils/rect.h>
58#include <utils/formats.h>
59
60#include "blit_engine_c2d.h"
61#include "hwc_debugger.h"
62
63#define __CLASS__ "BlitEngineC2D"
64
65// TODO(user): Remove pragma after fixing sign conversion errors
66#if defined(__clang__)
67#pragma clang diagnostic push
68#pragma clang diagnostic ignored "-Wsign-conversion"
69#endif
70
71namespace sdm {
72
73
74BlitEngineC2d::RegionIterator::RegionIterator(LayerRectArray rect) {
75  rect_array = rect;
76  r.end = INT(rect.count);
77  r.current = 0;
78  this->next = iterate;
79}
80
81int BlitEngineC2d::RegionIterator::iterate(copybit_region_t const *self, copybit_rect_t *rect) {
82  if (!self || !rect) {
83    DLOGE("iterate invalid parameters");
84    return 0;
85  }
86
87  RegionIterator const *me = static_cast<RegionIterator const*>(self);
88  if (me->r.current != me->r.end) {
89    rect->l = INT(me->rect_array.rect[me->r.current].left);
90    rect->t = INT(me->rect_array.rect[me->r.current].top);
91    rect->r = INT(me->rect_array.rect[me->r.current].right);
92    rect->b = INT(me->rect_array.rect[me->r.current].bottom);
93    me->r.current++;
94    return 1;
95  }
96  return 0;
97}
98
99BlitEngineC2d::BlitEngineC2d() {
100  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
101    blit_target_buffer_[i] = NULL;
102    release_fence_fd_[i] = -1;
103  }
104
105  HWCDebugHandler::Get()->GetProperty("persist.hwc.blit.comp", &blit_supported_);
106}
107
108BlitEngineC2d::~BlitEngineC2d() {
109  if (blit_engine_c2d_) {
110    copybit_close(blit_engine_c2d_);
111    blit_engine_c2d_ = NULL;
112  }
113  FreeBlitTargetBuffers();
114}
115
116int BlitEngineC2d::Init() {
117  if (!blit_supported_) {
118    return -1;
119  }
120
121  hw_module_t const *module;
122  if (hw_get_module("copybit", &module) == 0) {
123    if (copybit_open(module, &blit_engine_c2d_) < 0) {
124      DLOGI("CopyBitC2D Open failed.");
125      return -1;
126    }
127    DLOGI("Opened Copybit Module");
128  } else {
129    DLOGI("Copybit HW Module not found");
130    return -1;
131  }
132
133  return 0;
134}
135
136void BlitEngineC2d::DeInit() {
137  FreeBlitTargetBuffers();
138  if (blit_engine_c2d_) {
139    copybit_close(blit_engine_c2d_);
140    blit_engine_c2d_ = NULL;
141  }
142}
143
144int BlitEngineC2d::AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format,
145                                             uint32_t usage) {
146  int status = 0;
147  if (width <= 0 || height <= 0) {
148    return false;
149  }
150
151  if (blit_target_buffer_[0]) {
152    // Free and reallocate the buffers if the w/h changes
153    if (INT(width) != blit_target_buffer_[0]->width ||
154        INT(height) != blit_target_buffer_[0]->height) {
155      FreeBlitTargetBuffers();
156    }
157  }
158
159  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
160    if (blit_target_buffer_[i] == NULL) {
161      status = alloc_buffer(&blit_target_buffer_[i], width, height, format, usage);
162    }
163    if (status < 0) {
164      DLOGE("Allocation of Blit target Buffer failed");
165      FreeBlitTargetBuffers();
166      break;
167    }
168  }
169
170  return status;
171}
172
173void BlitEngineC2d::FreeBlitTargetBuffers() {
174  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
175    private_handle_t **target_buffer = &blit_target_buffer_[i];
176    if (*target_buffer) {
177      // Free the valid fence
178      if (release_fence_fd_[i] >= 0) {
179        close(release_fence_fd_[i]);
180        release_fence_fd_[i] = -1;
181      }
182      free_buffer(*target_buffer);
183      *target_buffer = NULL;
184    }
185  }
186}
187
188int BlitEngineC2d::ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect) {
189  int status = 0;
190  copybit_rect_t clear_rect = {INT(rect.left), INT(rect.top), INT(rect.right), INT(rect.bottom)};
191
192  copybit_image_t buffer;
193  buffer.w = ALIGN((hnd->width), 32);
194  buffer.h = hnd->height;
195  buffer.format = hnd->format;
196  buffer.base = reinterpret_cast<void *>(hnd->base);
197  buffer.handle = reinterpret_cast<native_handle_t *>(hnd);
198  int dst_format_mode = COPYBIT_LINEAR;
199  if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
200    dst_format_mode = COPYBIT_UBWC_COMPRESSED;
201  }
202  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DST_FORMAT_MODE, dst_format_mode);
203
204  status = blit_engine_c2d_->clear(blit_engine_c2d_, &buffer, &clear_rect);
205  return status;
206}
207
208void BlitEngineC2d::PostCommit(LayerStack *layer_stack) {
209  int fence_fd = -1;
210  uint32_t count = 0;
211  int fd = -1;
212
213  for (uint32_t i = blit_target_start_index_-2; (i > 0) && (count < num_blit_target_); i--) {
214    Layer &layer = layer_stack->layers[i];
215    LayerBuffer *layer_buffer = layer.input_buffer;
216    if (layer.composition == kCompositionBlit) {
217      int index = blit_target_start_index_ + count;
218      layer_buffer->release_fence_fd = layer_stack->layers[index].input_buffer->release_fence_fd;
219      fence_fd = layer_buffer->release_fence_fd;
220      close(layer_buffer->acquire_fence_fd);
221      layer_buffer->acquire_fence_fd = -1;
222      layer_stack->layers[index].input_buffer->release_fence_fd = -1;
223      fd = layer_stack->layers[index].input_buffer->acquire_fence_fd;
224      layer_stack->layers[index].input_buffer->acquire_fence_fd = -1;
225      count++;
226    }
227  }
228
229  if (fd >= 0) {
230    // Close the C2D fence FD
231    close(fd);
232  }
233  SetReleaseFence(fence_fd);
234}
235
236// Sync wait to close the previous fd
237void BlitEngineC2d::SetReleaseFence(int fd) {
238  if (release_fence_fd_[current_blit_target_index_] >= 0) {
239    int ret = -1;
240    ret = sync_wait(release_fence_fd_[current_blit_target_index_], 1000);
241    if (ret < 0) {
242      DLOGE("sync_wait error! errno = %d, err str = %s", errno, strerror(errno));
243    }
244    close(release_fence_fd_[current_blit_target_index_]);
245  }
246  release_fence_fd_[current_blit_target_index_] = dup(fd);
247}
248
249bool BlitEngineC2d::BlitActive() {
250  return blit_active_;
251}
252
253void BlitEngineC2d::SetFrameDumpConfig(uint32_t count) {
254  dump_frame_count_ = count;
255  dump_frame_index_ = 0;
256}
257
258int BlitEngineC2d::Prepare(LayerStack *layer_stack) {
259  blit_target_start_index_ = 0;
260
261  uint32_t gpu_target_index = layer_stack->layer_count-1;
262  uint32_t i = INT(layer_stack->layer_count-1);
263
264  for (i = 0; i < layer_stack->layer_count; i++) {
265    Layer &layer = layer_stack->layers[i];
266    if (!blit_supported_) {
267      return -1;
268    }
269
270    // No 10 bit support for C2D
271    if (Is10BitFormat(layer.input_buffer->format)) {
272      return -1;
273    }
274
275    if (layer.composition == kCompositionGPUTarget) {
276      // Need FBT size for allocating buffers
277      gpu_target_index = i;
278      break;
279    }
280  }
281
282  if ((layer_stack->layer_count-1) == gpu_target_index) {
283    // No blit target layer
284    return -1;
285  }
286
287  blit_target_start_index_ = ++i;
288  num_blit_target_ = layer_stack->layer_count - blit_target_start_index_;
289
290  LayerBuffer *layer_buffer = layer_stack->layers[gpu_target_index].input_buffer;
291  int fbwidth = INT(layer_buffer->width);
292  int fbheight = INT(layer_buffer->height);
293  if ((fbwidth < 0) || (fbheight < 0)) {
294    return -1;
295  }
296
297  current_blit_target_index_ = (current_blit_target_index_ + 1) % kNumBlitTargetBuffers;
298  int k = blit_target_start_index_;
299
300  for (uint32_t j = 0; j < num_blit_target_; j++, k++) {
301    Layer &layer = layer_stack->layers[k];
302    LayerBuffer *layer_buffer = layer.input_buffer;
303
304    // Set the buffer height and width
305    layer_buffer->width = fbwidth;
306    layer_buffer->height = fbheight/3;
307
308    layer.plane_alpha = 0xFF;
309    layer.blending = kBlendingOpaque;
310    layer.composition = kCompositionBlitTarget;
311    layer.frame_rate = layer_stack->layers[gpu_target_index].frame_rate;
312  }
313
314  return 0;
315}
316
317int BlitEngineC2d::PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
318  int status = 0;
319  uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
320  int target_width = 0;
321  int target_height = 0;
322  uint32_t processed_blit = 0;
323  LayerRect dst_rects[kMaxBlitTargetLayers];
324  bool blit_needed = false;
325  uint32_t usage = 0;
326
327  if (!num_app_layers) {
328    return -1;
329  }
330
331  for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_); i--) {
332    Layer &layer = layer_stack->layers[i];
333    if (layer.composition != kCompositionBlit) {
334      continue;
335    }
336    blit_needed = true;
337    layer_stack->flags.attributes_changed = true;
338
339    Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
340    LayerRect &blit_src_rect = blit_layer.src_rect;
341    int width = INT(layer.dst_rect.right - layer.dst_rect.left);
342    int height = INT(layer.dst_rect.bottom - layer.dst_rect.top);
343    usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE;
344    if (blit_engine_c2d_->get(blit_engine_c2d_, COPYBIT_UBWC_SUPPORT) > 0) {
345      usage |= GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
346    }
347    // TODO(user): FrameBuffer is assumed to be RGBA
348    AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height,
349                                 INT(HAL_PIXEL_FORMAT_RGBA_8888), usage, width, height);
350
351    target_width = MAX(target_width, width);
352    target_height += height;
353
354    // Left will be zero always
355    dst_rects[processed_blit].top = FLOAT(target_height - height);
356    dst_rects[processed_blit].right = dst_rects[processed_blit].left +
357                                      (layer.dst_rect.right - layer.dst_rect.left);
358    dst_rects[processed_blit].bottom = (dst_rects[processed_blit].top +
359                                      (layer.dst_rect.bottom - layer.dst_rect.top));
360    blit_src_rect = dst_rects[processed_blit];
361    processed_blit++;
362  }
363
364  // Allocate a single buffer of RGBA8888 format
365  if (blit_needed && (AllocateBlitTargetBuffers(target_width, target_height,
366                                                HAL_PIXEL_FORMAT_RGBA_8888, usage) < 0)) {
367      status = -1;
368      return status;
369  }
370
371  if (blit_needed) {
372    for (uint32_t j = 0; j < num_blit_target_; j++) {
373      Layer &layer = layer_stack->layers[j + content_list->numHwLayers];
374      private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
375      // Set the fd information
376      if (layer.input_buffer) {
377        layer.input_buffer->width = target_width;
378        layer.input_buffer->height = target_height;
379        if (target_buffer->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
380          layer.input_buffer->format = kFormatRGBA8888Ubwc;
381        }
382        layer.input_buffer->planes[0].fd = target_buffer->fd;
383        layer.input_buffer->planes[0].offset = 0;
384        layer.input_buffer->planes[0].stride = target_buffer->width;
385      }
386    }
387  }
388
389  return status;
390}
391
392int BlitEngineC2d::Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
393  int fd = -1;
394  int status = 0;
395  bool hybrid_present = false;
396  uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
397  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
398  blit_active_ = false;
399
400  if (!num_app_layers) {
401    return -1;
402  }
403
404  // if not Blit Targets return
405  for (uint32_t i = 0; i < num_app_layers; i++) {
406    Layer &layer = layer_stack->layers[i];
407    if (layer.composition == kCompositionHybrid || layer.composition == kCompositionBlit) {
408      hybrid_present = true;
409    }
410  }
411
412  if (!hybrid_present) {
413    return status;
414  }
415
416  // Clear blit target buffer
417  LayerRect clear_rect;
418  clear_rect.left =  0;
419  clear_rect.top = 0;
420  clear_rect.right = FLOAT(target_buffer->width);
421  clear_rect.bottom = FLOAT(target_buffer->height);
422  ClearTargetBuffer(target_buffer, clear_rect);
423
424  int copybit_layer_count = 0;
425  uint32_t processed_blit = 0;
426  for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_) &&
427      (status == 0); i--) {
428    Layer &layer = layer_stack->layers[i];
429    if (layer.composition != kCompositionBlit) {
430      continue;
431    }
432
433    for (uint32_t k = 0; k <= i; k++) {
434      Layer &bottom_layer = layer_stack->layers[k];
435      LayerBuffer *layer_buffer = bottom_layer.input_buffer;
436      // if layer below the blit layer does not intersect, ignore that layer
437      LayerRect inter_sect = Intersection(layer.dst_rect, bottom_layer.dst_rect);
438      if (bottom_layer.composition != kCompositionHybrid && !IsValid(inter_sect)) {
439        continue;
440      }
441      if (bottom_layer.composition == kCompositionGPU ||
442          bottom_layer.composition == kCompositionSDE ||
443          bottom_layer.composition == kCompositionGPUTarget) {
444        continue;
445      }
446
447      // For each layer marked as Hybrid, wait for acquire fence and then blit using the C2D
448      if (layer_buffer->acquire_fence_fd >= 0) {
449        // Wait for acquire fence on the App buffers.
450        if (sync_wait(layer_buffer->acquire_fence_fd, 1000) < 0) {
451          DLOGE("sync_wait error!! error no = %d err str = %s", errno, strerror(errno));
452        }
453        layer_buffer->acquire_fence_fd = -1;
454      }
455      hwc_layer_1_t *hwc_layer = &content_list->hwLayers[k];
456      LayerRect src_rect = bottom_layer.blit_regions.rect[processed_blit];
457      Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
458      LayerRect dest_rect = blit_layer.src_rect;
459      int ret_val = DrawRectUsingCopybit(hwc_layer, &bottom_layer, src_rect, dest_rect);
460      copybit_layer_count++;
461      if (ret_val < 0) {
462        copybit_layer_count = 0;
463        DLOGE("DrawRectUsingCopyBit failed");
464        status = -1;
465        break;
466      }
467    }
468    processed_blit++;
469  }
470
471  if (copybit_layer_count) {
472    blit_active_ = true;
473    blit_engine_c2d_->flush_get_fence(blit_engine_c2d_, &fd);
474  }
475
476  if (blit_active_) {
477    // dump the render buffer
478    DumpBlitTargetBuffer(fd);
479
480    // Set the fd to the LayerStack BlitTargets fd
481    for (uint32_t k = blit_target_start_index_; k < layer_stack->layer_count; k++) {
482      Layer &layer = layer_stack->layers[k];
483      LayerBuffer *layer_buffer = layer.input_buffer;
484      layer_buffer->acquire_fence_fd = fd;
485    }
486  }
487
488  return status;
489}
490
491int BlitEngineC2d::DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer,
492                                        LayerRect blit_rect, LayerRect blit_dest_Rect) {
493  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
494  const private_handle_t *hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
495  LayerBuffer *layer_buffer = layer->input_buffer;
496
497  // Set the Copybit Source
498  copybit_image_t src;
499  src.handle = const_cast<native_handle_t *>(hwc_layer->handle);
500  src.w = hnd->width;
501  src.h = hnd->height;
502  src.base = reinterpret_cast<void *>(hnd->base);
503  src.format = hnd->format;
504  src.horiz_padding = 0;
505  src.vert_padding = 0;
506
507  // Copybit source rect
508  copybit_rect_t src_rect = {INT(blit_rect.left), INT(blit_rect.top), INT(blit_rect.right),
509                            INT(blit_rect.bottom)};
510
511  // Copybit destination rect
512  copybit_rect_t dst_rect = {INT(blit_dest_Rect.left), INT(blit_dest_Rect.top),
513                            INT(blit_dest_Rect.right), INT(blit_dest_Rect.bottom)};
514
515  // Copybit destination buffer
516  copybit_image_t dst;
517  dst.handle = static_cast<native_handle_t *>(target_buffer);
518  dst.w = ALIGN(target_buffer->width, 32);
519  dst.h = ALIGN((target_buffer->height), 32);
520  dst.base = reinterpret_cast<void *>(target_buffer->base);
521  dst.format = target_buffer->format;
522
523  // Copybit region is the destRect
524  LayerRect region_rect;
525  region_rect.left = FLOAT(dst_rect.l);
526  region_rect.top = FLOAT(dst_rect.t);
527  region_rect.right = FLOAT(dst_rect.r);
528  region_rect.bottom = FLOAT(dst_rect.b);
529
530  LayerRectArray region;
531  region.count = 1;
532  region.rect  = &region_rect;
533  RegionIterator copybitRegion(region);
534  int acquireFd = layer_buffer->acquire_fence_fd;
535
536  // FRAMEBUFFER_WIDTH/HEIGHT for c2d is the target buffer w/h
537  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_WIDTH,
538                                  target_buffer->width);
539  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_HEIGHT,
540                                  target_buffer->height);
541  int transform = 0;
542  if (layer->transform.rotation != 0.0f) transform |= COPYBIT_TRANSFORM_ROT_90;
543  if (layer->transform.flip_horizontal) transform |= COPYBIT_TRANSFORM_FLIP_H;
544  if (layer->transform.flip_vertical) transform |= COPYBIT_TRANSFORM_FLIP_V;
545  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_TRANSFORM, transform);
546  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_PLANE_ALPHA, hwc_layer->planeAlpha);
547  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_BLEND_MODE, hwc_layer->blending);
548  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DITHER,
549    (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
550
551  int src_format_mode = COPYBIT_LINEAR;
552  if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
553    src_format_mode = COPYBIT_UBWC_COMPRESSED;
554  }
555  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_SRC_FORMAT_MODE, src_format_mode);
556
557  blit_engine_c2d_->set_sync(blit_engine_c2d_, acquireFd);
558  int err = blit_engine_c2d_->stretch(blit_engine_c2d_, &dst, &src, &dst_rect, &src_rect,
559                                      &copybitRegion);
560
561  if (err < 0) {
562    DLOGE("copybit stretch failed");
563  }
564
565  return err;
566}
567
568void BlitEngineC2d::DumpBlitTargetBuffer(int fd) {
569  if (!dump_frame_count_) {
570    return;
571  }
572
573  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
574
575  if (fd >= 0) {
576    int error = sync_wait(fd, 1000);
577    if (error < 0) {
578      DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
579      return;
580    }
581  }
582
583  char dump_file_name[PATH_MAX];
584  size_t result = 0;
585  snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
586           "/blit_target_%d.raw", (dump_frame_index_));
587  FILE* fp = fopen(dump_file_name, "w+");
588  if (fp) {
589    result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
590    fclose(fp);
591  }
592  dump_frame_count_--;
593  dump_frame_index_++;
594}
595
596}  // namespace sdm
597#if defined(__clang__)
598#pragma clang diagnostic pop
599#endif
600
601