Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: cc/resources/texture_uploader.cc

Issue 1533773002: Delete CC. (Closed) Base URL: git@github.com:domokit/mojo.git@cl-2e
Patch Set: rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/resources/texture_uploader.h ('k') | cc/resources/texture_uploader_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cc/resources/texture_uploader.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/metrics/histogram.h"
11 #include "base/trace_event/trace_event.h"
12 #include "cc/base/util.h"
13 #include "cc/resources/resource.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "gpu/command_buffer/client/gles2_interface.h"
16 #include "third_party/khronos/GLES2/gl2.h"
17 #include "third_party/khronos/GLES2/gl2ext.h"
18 #include "ui/gfx/geometry/rect.h"
19 #include "ui/gfx/geometry/vector2d.h"
20
21 using gpu::gles2::GLES2Interface;
22
23 namespace {
24
25 // How many previous uploads to use when predicting future throughput.
26 static const size_t kUploadHistorySizeMax = 1000;
27 static const size_t kUploadHistorySizeInitial = 100;
28
29 // Global estimated number of textures per second to maintain estimates across
30 // subsequent instances of TextureUploader.
31 // More than one thread will not access this variable, so we do not need to
32 // synchronize access.
33 static const double kDefaultEstimatedTexturesPerSecond = 48.0 * 60.0;
34
35 // Flush interval when performing texture uploads.
36 static const size_t kTextureUploadFlushPeriod = 4;
37
38 } // anonymous namespace
39
40 namespace cc {
41
42 TextureUploader::Query::Query(GLES2Interface* gl)
43 : gl_(gl),
44 query_id_(0),
45 value_(0),
46 has_value_(false),
47 is_non_blocking_(false) {
48 gl_->GenQueriesEXT(1, &query_id_);
49 }
50
51 TextureUploader::Query::~Query() { gl_->DeleteQueriesEXT(1, &query_id_); }
52
53 void TextureUploader::Query::Begin() {
54 has_value_ = false;
55 is_non_blocking_ = false;
56 gl_->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_);
57 }
58
59 void TextureUploader::Query::End() {
60 gl_->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
61 }
62
63 bool TextureUploader::Query::IsPending() {
64 unsigned available = 1;
65 gl_->GetQueryObjectuivEXT(
66 query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
67 return !available;
68 }
69
70 unsigned TextureUploader::Query::Value() {
71 if (!has_value_) {
72 gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_);
73 has_value_ = true;
74 }
75 return value_;
76 }
77
78 TextureUploader::TextureUploader(GLES2Interface* gl)
79 : gl_(gl),
80 num_blocking_texture_uploads_(0),
81 sub_image_size_(0),
82 num_texture_uploads_since_last_flush_(0) {
83 for (size_t i = kUploadHistorySizeInitial; i > 0; i--)
84 textures_per_second_history_.insert(kDefaultEstimatedTexturesPerSecond);
85 }
86
87 TextureUploader::~TextureUploader() {}
88
89 size_t TextureUploader::NumBlockingUploads() {
90 ProcessQueries();
91 return num_blocking_texture_uploads_;
92 }
93
94 void TextureUploader::MarkPendingUploadsAsNonBlocking() {
95 for (ScopedPtrDeque<Query>::iterator it = pending_queries_.begin();
96 it != pending_queries_.end();
97 ++it) {
98 if ((*it)->is_non_blocking())
99 continue;
100
101 num_blocking_texture_uploads_--;
102 (*it)->mark_as_non_blocking();
103 }
104
105 DCHECK(!num_blocking_texture_uploads_);
106 }
107
108 double TextureUploader::EstimatedTexturesPerSecond() {
109 ProcessQueries();
110
111 // Use the median as our estimate.
112 std::multiset<double>::iterator median = textures_per_second_history_.begin();
113 std::advance(median, textures_per_second_history_.size() / 2);
114 return *median;
115 }
116
117 void TextureUploader::BeginQuery() {
118 // Check to see if any of the pending queries are free before allocating a
119 // new one. If this is not done, queries may be allocated without bound.
120 // http://crbug.com/398072
121 if (available_queries_.empty())
122 ProcessQueries();
123
124 if (available_queries_.empty())
125 available_queries_.push_back(Query::Create(gl_));
126
127 available_queries_.front()->Begin();
128 }
129
130 void TextureUploader::EndQuery() {
131 available_queries_.front()->End();
132 pending_queries_.push_back(available_queries_.take_front());
133 num_blocking_texture_uploads_++;
134 }
135
136 void TextureUploader::Upload(const uint8* image,
137 const gfx::Rect& image_rect,
138 const gfx::Rect& source_rect,
139 gfx::Vector2d dest_offset,
140 ResourceFormat format,
141 const gfx::Size& size) {
142 CHECK(image_rect.Contains(source_rect));
143
144 bool is_full_upload = dest_offset.IsZero() && source_rect.size() == size;
145
146 if (is_full_upload)
147 BeginQuery();
148
149 UploadWithMapTexSubImage(image, image_rect, source_rect, dest_offset, format);
150
151 if (is_full_upload)
152 EndQuery();
153
154 num_texture_uploads_since_last_flush_++;
155 if (num_texture_uploads_since_last_flush_ >= kTextureUploadFlushPeriod)
156 Flush();
157 }
158
159 void TextureUploader::Flush() {
160 if (!num_texture_uploads_since_last_flush_)
161 return;
162
163 gl_->ShallowFlushCHROMIUM();
164
165 num_texture_uploads_since_last_flush_ = 0;
166 }
167
168 void TextureUploader::ReleaseCachedQueries() {
169 ProcessQueries();
170 available_queries_.clear();
171 }
172
173 void TextureUploader::UploadWithTexSubImage(const uint8* image,
174 const gfx::Rect& image_rect,
175 const gfx::Rect& source_rect,
176 gfx::Vector2d dest_offset,
177 ResourceFormat format) {
178 TRACE_EVENT0("cc", "TextureUploader::UploadWithTexSubImage");
179
180 // Early-out if this is a no-op, and assert that |image| be valid if this is
181 // not a no-op.
182 if (source_rect.IsEmpty())
183 return;
184 DCHECK(image);
185
186 // Offset from image-rect to source-rect.
187 gfx::Vector2d offset(source_rect.origin() - image_rect.origin());
188
189 const uint8* pixel_source;
190 unsigned bytes_per_pixel = BitsPerPixel(format) / 8;
191 // Use 4-byte row alignment (OpenGL default) for upload performance.
192 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
193 unsigned upload_image_stride =
194 RoundUp(bytes_per_pixel * source_rect.width(), 4u);
195
196 if (upload_image_stride == image_rect.width() * bytes_per_pixel &&
197 !offset.x()) {
198 pixel_source = &image[image_rect.width() * bytes_per_pixel * offset.y()];
199 } else {
200 size_t needed_size = upload_image_stride * source_rect.height();
201 if (sub_image_size_ < needed_size) {
202 sub_image_.reset(new uint8[needed_size]);
203 sub_image_size_ = needed_size;
204 }
205 // Strides not equal, so do a row-by-row memcpy from the
206 // paint results into a temp buffer for uploading.
207 for (int row = 0; row < source_rect.height(); ++row)
208 memcpy(&sub_image_[upload_image_stride * row],
209 &image[bytes_per_pixel *
210 (offset.x() + (offset.y() + row) * image_rect.width())],
211 source_rect.width() * bytes_per_pixel);
212
213 pixel_source = &sub_image_[0];
214 }
215
216 gl_->TexSubImage2D(GL_TEXTURE_2D,
217 0,
218 dest_offset.x(),
219 dest_offset.y(),
220 source_rect.width(),
221 source_rect.height(),
222 GLDataFormat(format),
223 GLDataType(format),
224 pixel_source);
225 }
226
227 void TextureUploader::UploadWithMapTexSubImage(const uint8* image,
228 const gfx::Rect& image_rect,
229 const gfx::Rect& source_rect,
230 gfx::Vector2d dest_offset,
231 ResourceFormat format) {
232 TRACE_EVENT0("cc", "TextureUploader::UploadWithMapTexSubImage");
233
234 // Early-out if this is a no-op, and assert that |image| be valid if this is
235 // not a no-op.
236 if (source_rect.IsEmpty())
237 return;
238 DCHECK(image);
239 // Compressed textures have no implementation of mapTexSubImage.
240 DCHECK_NE(ETC1, format);
241
242 // Offset from image-rect to source-rect.
243 gfx::Vector2d offset(source_rect.origin() - image_rect.origin());
244
245 unsigned bytes_per_pixel = BitsPerPixel(format) / 8;
246 // Use 4-byte row alignment (OpenGL default) for upload performance.
247 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
248 unsigned upload_image_stride =
249 RoundUp(bytes_per_pixel * source_rect.width(), 4u);
250
251 // Upload tile data via a mapped transfer buffer
252 uint8* pixel_dest =
253 static_cast<uint8*>(gl_->MapTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
254 0,
255 dest_offset.x(),
256 dest_offset.y(),
257 source_rect.width(),
258 source_rect.height(),
259 GLDataFormat(format),
260 GLDataType(format),
261 GL_WRITE_ONLY));
262
263 if (!pixel_dest) {
264 UploadWithTexSubImage(image, image_rect, source_rect, dest_offset, format);
265 return;
266 }
267
268 if (upload_image_stride == image_rect.width() * bytes_per_pixel &&
269 !offset.x()) {
270 memcpy(pixel_dest,
271 &image[image_rect.width() * bytes_per_pixel * offset.y()],
272 source_rect.height() * image_rect.width() * bytes_per_pixel);
273 } else {
274 // Strides not equal, so do a row-by-row memcpy from the
275 // paint results into the pixel_dest.
276 for (int row = 0; row < source_rect.height(); ++row) {
277 memcpy(&pixel_dest[upload_image_stride * row],
278 &image[bytes_per_pixel *
279 (offset.x() + (offset.y() + row) * image_rect.width())],
280 source_rect.width() * bytes_per_pixel);
281 }
282 }
283
284 gl_->UnmapTexSubImage2DCHROMIUM(pixel_dest);
285 }
286
287 void TextureUploader::ProcessQueries() {
288 while (!pending_queries_.empty()) {
289 if (pending_queries_.front()->IsPending())
290 break;
291
292 unsigned us_elapsed = pending_queries_.front()->Value();
293 UMA_HISTOGRAM_CUSTOM_COUNTS(
294 "Renderer4.TextureGpuUploadTimeUS", us_elapsed, 0, 100000, 50);
295
296 // Clamp the queries to saner values in case the queries fail.
297 us_elapsed = std::max(1u, us_elapsed);
298 us_elapsed = std::min(15000u, us_elapsed);
299
300 if (!pending_queries_.front()->is_non_blocking())
301 num_blocking_texture_uploads_--;
302
303 // Remove the min and max value from our history and insert the new one.
304 double textures_per_second = 1.0 / (us_elapsed * 1e-6);
305 if (textures_per_second_history_.size() >= kUploadHistorySizeMax) {
306 textures_per_second_history_.erase(textures_per_second_history_.begin());
307 textures_per_second_history_.erase(--textures_per_second_history_.end());
308 }
309 textures_per_second_history_.insert(textures_per_second);
310
311 available_queries_.push_back(pending_queries_.take_front());
312 }
313 }
314
315 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/texture_uploader.h ('k') | cc/resources/texture_uploader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698