File: copy_output_request.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (179 lines) | stat: -rw-r--r-- 6,359 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/viz/common/frame_sinks/copy_output_request.h"

#include <algorithm>
#include <utility>

#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "third_party/skia/include/core/SkBitmap.h"

namespace {

constexpr int kMaxPendingSendResult = 4;

const char* ResultFormatToShortString(
    viz::CopyOutputRequest::ResultFormat result_format) {
  switch (result_format) {
    case viz::CopyOutputRequest::ResultFormat::RGBA:
      return "RGBA";
    case viz::CopyOutputRequest::ResultFormat::I420_PLANES:
      return "I420";
    case viz::CopyOutputRequest::ResultFormat::NV12:
      return "NV12";
  }
}

const char* ResultDestinationToShortString(
    viz::CopyOutputRequest::ResultDestination result_destination) {
  switch (result_destination) {
    case viz::CopyOutputRequest::ResultDestination::kSystemMemory:
      return "CPU";
    case viz::CopyOutputRequest::ResultDestination::kNativeTextures:
      return "GPU";
  }
}

int g_pending_send_result_count = 0;

base::Lock& GetPendingSendResultLock() {
  static base::NoDestructor<base::Lock> lock;
  return *lock;
}

}  // namespace

namespace viz {

CopyOutputRequest::CopyOutputRequest(ResultFormat result_format,
                                     ResultDestination result_destination,
                                     CopyOutputRequestCallback result_callback)
    : result_format_(result_format),
      result_destination_(result_destination),
      result_callback_(std::move(result_callback)),
      result_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
      scale_from_(1, 1),
      scale_to_(1, 1) {
  // If format is I420_PLANES, the result must be in system memory. Returning
  // I420_PLANES via textures is not yet supported.
  DCHECK(result_format_ != ResultFormat::I420_PLANES ||
         result_destination_ == ResultDestination::kSystemMemory);

  DCHECK(!result_callback_.is_null());
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("viz", "CopyOutputRequest", this);
}

CopyOutputRequest::~CopyOutputRequest() {
  if (!result_callback_.is_null()) {
    // Send an empty result to indicate the request was never satisfied.
    SendResult(std::make_unique<CopyOutputResult>(
        result_format_, result_destination_, gfx::Rect(), false));
  }
}

std::string CopyOutputRequest::ToString() const {
  return base::StringPrintf(
      "[%s] -%s→%s-> [%s] @ [%s, %s] %s",
      has_area() ? area().ToString().c_str() : "noclip",
      scale_from().ToString().c_str(), scale_to().ToString().c_str(),
      has_result_selection() ? result_selection().ToString().c_str()
                             : "noclamp",
      ResultFormatToShortString(result_format()),
      ResultDestinationToShortString(result_destination()),
      has_blit_request() ? blit_request_->ToString().c_str() : "noblit");
}

void CopyOutputRequest::SetScaleRatio(const gfx::Vector2d& scale_from,
                                      const gfx::Vector2d& scale_to) {
  // These are CHECKs, and not DCHECKs, because it's critical that crash report
  // bugs be tied to the client callpoint rather than the later mojo or service-
  // side processing of the CopyOutputRequest.
  CHECK_GT(scale_from.x(), 0);
  CHECK_GT(scale_from.y(), 0);
  CHECK_GT(scale_to.x(), 0);
  CHECK_GT(scale_to.y(), 0);

  scale_from_ = scale_from;
  scale_to_ = scale_to;
}

void CopyOutputRequest::SetUniformScaleRatio(int scale_from, int scale_to) {
  // See note in SetScaleRatio() as to why these are CHECKs and not DCHECKs.
  CHECK_GT(scale_from, 0);
  CHECK_GT(scale_to, 0);

  scale_from_ = gfx::Vector2d(scale_from, scale_from);
  scale_to_ = gfx::Vector2d(scale_to, scale_to);
}

void CopyOutputRequest::set_blit_request(BlitRequest blit_request) {
  DCHECK(!blit_request_);
  DCHECK_EQ(result_destination(), ResultDestination::kNativeTextures);
  DCHECK(result_format() == ResultFormat::NV12 ||
         result_format() == ResultFormat::RGBA);
  DCHECK(has_result_selection());

  if (result_format() == ResultFormat::NV12) {
    // Destination region must start at an even offset for NV12 results:
    DCHECK_EQ(blit_request.destination_region_offset().x() % 2, 0);
    DCHECK_EQ(blit_request.destination_region_offset().y() % 2, 0);
  }

  CHECK(!blit_request.mailbox().IsZero());

  blit_request_ = std::move(blit_request);
}

void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) {
  TRACE_EVENT_NESTABLE_ASYNC_END2(
      "viz", "CopyOutputRequest", this, "success", !result->IsEmpty(),
      "has_provided_task_runner", !!result_task_runner_);
  CHECK(result_task_runner_);
  auto task = base::BindOnce(std::move(result_callback_), std::move(result));

  if (send_result_delay_.is_zero()) {
    result_task_runner_->PostTask(FROM_HERE, std::move(task));
  } else {
    base::AutoLock locked_counter(GetPendingSendResultLock());
    if (g_pending_send_result_count >= kMaxPendingSendResult) {
      result_task_runner_->PostTask(FROM_HERE, std::move(task));
    } else {
      g_pending_send_result_count++;
      result_task_runner_->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(
              [](base::OnceClosure callback) {
                std::move(callback).Run();
                base::AutoLock locked_counter(GetPendingSendResultLock());
                g_pending_send_result_count--;
              },
              std::move(task)),
          send_result_delay_);
    }
  }
  // Remove the reference to the task runner (no-op if we didn't have one).
  result_task_runner_ = nullptr;
}

bool CopyOutputRequest::SendsResultsInCurrentSequence() const {
  return result_task_runner_ &&
         result_task_runner_->RunsTasksInCurrentSequence();
}

// static
std::unique_ptr<CopyOutputRequest> CopyOutputRequest::CreateStubForTesting() {
  return std::make_unique<CopyOutputRequest>(
      ResultFormat::RGBA, ResultDestination::kSystemMemory,
      base::BindOnce([](std::unique_ptr<CopyOutputResult>) {}));
}

}  // namespace viz