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 = ®ion_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 ©bitRegion); 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