OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 | 6 |
7 #include "cc/texture_uploader.h" | 7 #include "cc/texture_uploader.h" |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/debug/alias.h" | 12 #include "base/debug/alias.h" |
13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
15 #include "cc/prioritized_texture.h" | 15 #include "cc/prioritized_texture.h" |
16 #include "third_party/khronos/GLES2/gl2.h" | 16 #include "third_party/khronos/GLES2/gl2.h" |
17 #include "third_party/khronos/GLES2/gl2ext.h" | 17 #include "third_party/khronos/GLES2/gl2ext.h" |
18 #include <public/WebGraphicsContext3D.h> | 18 #include <public/WebGraphicsContext3D.h> |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
22 // How many previous uploads to use when predicting future throughput. | 22 // How many previous uploads to use when predicting future throughput. |
23 static const size_t uploadHistorySize = 100; | 23 static const size_t uploadHistorySizeMax = 1000; |
| 24 static const size_t uploadHistorySizeInitial = 100; |
24 | 25 |
25 // Global estimated number of textures per second to maintain estimates across | 26 // Global estimated number of textures per second to maintain estimates across |
26 // subsequent instances of TextureUploader. | 27 // subsequent instances of TextureUploader. |
27 // More than one thread will not access this variable, so we do not need to sync
hronize access. | 28 // More than one thread will not access this variable, so we do not need to sync
hronize access. |
28 static double estimatedTexturesPerSecondGlobal = 48.0 * 60.0; | 29 static const double defaultEstimatedTexturesPerSecond = 48.0 * 60.0; |
29 | 30 |
30 } // anonymous namespace | 31 } // anonymous namespace |
31 | 32 |
32 namespace cc { | 33 namespace cc { |
33 | 34 |
34 TextureUploader::Query::Query(WebKit::WebGraphicsContext3D* context) | 35 TextureUploader::Query::Query(WebKit::WebGraphicsContext3D* context) |
35 : m_context(context) | 36 : m_context(context) |
36 , m_queryId(0) | 37 , m_queryId(0) |
37 , m_value(0) | 38 , m_value(0) |
38 , m_hasValue(false) | 39 , m_hasValue(false) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 } | 81 } |
81 | 82 |
82 bool TextureUploader::Query::isNonBlocking() | 83 bool TextureUploader::Query::isNonBlocking() |
83 { | 84 { |
84 return m_isNonBlocking; | 85 return m_isNonBlocking; |
85 } | 86 } |
86 | 87 |
87 TextureUploader::TextureUploader( | 88 TextureUploader::TextureUploader( |
88 WebKit::WebGraphicsContext3D* context, bool useMapTexSubImage) | 89 WebKit::WebGraphicsContext3D* context, bool useMapTexSubImage) |
89 : m_context(context) | 90 : m_context(context) |
90 , m_texturesPerSecondHistory(uploadHistorySize, | |
91 estimatedTexturesPerSecondGlobal) | |
92 , m_numBlockingTextureUploads(0) | 91 , m_numBlockingTextureUploads(0) |
93 , m_useMapTexSubImage(useMapTexSubImage) | 92 , m_useMapTexSubImage(useMapTexSubImage) |
94 , m_subImageSize(0) | 93 , m_subImageSize(0) |
95 { | 94 { |
| 95 for (size_t i = uploadHistorySizeInitial; i > 0; i--) |
| 96 m_texturesPerSecondHistory.insert(defaultEstimatedTexturesPerSecond); |
96 } | 97 } |
97 | 98 |
98 TextureUploader::~TextureUploader() | 99 TextureUploader::~TextureUploader() |
99 { | 100 { |
100 } | 101 } |
101 | 102 |
102 size_t TextureUploader::numBlockingUploads() | 103 size_t TextureUploader::numBlockingUploads() |
103 { | 104 { |
104 processQueries(); | 105 processQueries(); |
105 return m_numBlockingTextureUploads; | 106 return m_numBlockingTextureUploads; |
(...skipping 10 matching lines...) Expand all Loading... |
116 (*it)->markAsNonBlocking(); | 117 (*it)->markAsNonBlocking(); |
117 } | 118 } |
118 | 119 |
119 DCHECK(!m_numBlockingTextureUploads); | 120 DCHECK(!m_numBlockingTextureUploads); |
120 } | 121 } |
121 | 122 |
122 double TextureUploader::estimatedTexturesPerSecond() | 123 double TextureUploader::estimatedTexturesPerSecond() |
123 { | 124 { |
124 processQueries(); | 125 processQueries(); |
125 | 126 |
126 // The history should never be empty because we initialize all elements with
an estimate. | 127 // Use the median as our estimate. |
127 DCHECK(m_texturesPerSecondHistory.size() == uploadHistorySize); | 128 std::multiset<double>::iterator median = m_texturesPerSecondHistory.begin(); |
128 | 129 std::advance(median, m_texturesPerSecondHistory.size() / 2); |
129 // Sort the history and use the median as our estimate. | 130 TRACE_COUNTER1("cc", "estimatedTexturesPerSecond", *median); |
130 std::vector<double> sortedHistory(m_texturesPerSecondHistory.begin(), | 131 return *median; |
131 m_texturesPerSecondHistory.end()); | |
132 std::sort(sortedHistory.begin(), sortedHistory.end()); | |
133 | |
134 estimatedTexturesPerSecondGlobal = sortedHistory[sortedHistory.size() * 2 /
3]; | |
135 TRACE_COUNTER1("cc", "estimatedTexturesPerSecond", estimatedTexturesPerSecon
dGlobal); | |
136 return estimatedTexturesPerSecondGlobal; | |
137 } | 132 } |
138 | 133 |
139 void TextureUploader::beginQuery() | 134 void TextureUploader::beginQuery() |
140 { | 135 { |
141 if (m_availableQueries.isEmpty()) | 136 if (m_availableQueries.isEmpty()) |
142 m_availableQueries.append(Query::create(m_context)); | 137 m_availableQueries.append(Query::create(m_context)); |
143 | 138 |
144 m_availableQueries.first()->begin(); | 139 m_availableQueries.first()->begin(); |
145 } | 140 } |
146 | 141 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
332 while (!m_pendingQueries.isEmpty()) { | 327 while (!m_pendingQueries.isEmpty()) { |
333 if (m_pendingQueries.first()->isPending()) | 328 if (m_pendingQueries.first()->isPending()) |
334 break; | 329 break; |
335 | 330 |
336 unsigned usElapsed = m_pendingQueries.first()->value(); | 331 unsigned usElapsed = m_pendingQueries.first()->value(); |
337 HISTOGRAM_CUSTOM_COUNTS("Renderer4.TextureGpuUploadTimeUS", usElapsed, 0
, 100000, 50); | 332 HISTOGRAM_CUSTOM_COUNTS("Renderer4.TextureGpuUploadTimeUS", usElapsed, 0
, 100000, 50); |
338 | 333 |
339 if (!m_pendingQueries.first()->isNonBlocking()) | 334 if (!m_pendingQueries.first()->isNonBlocking()) |
340 m_numBlockingTextureUploads--; | 335 m_numBlockingTextureUploads--; |
341 | 336 |
342 // Remove the oldest values from our history and insert the new one | 337 // Remove the min and max value from our history and insert the new one. |
343 double texturesPerSecond = 1.0 / (usElapsed * 1e-6); | 338 double texturesPerSecond = 1.0 / (usElapsed * 1e-6); |
344 m_texturesPerSecondHistory.pop_back(); | 339 if (m_texturesPerSecondHistory.size() >= uploadHistorySizeMax) { |
345 m_texturesPerSecondHistory.push_front(texturesPerSecond); | 340 m_texturesPerSecondHistory.erase(m_texturesPerSecondHistory.begin())
; |
| 341 m_texturesPerSecondHistory.erase(--m_texturesPerSecondHistory.end())
; |
| 342 } |
| 343 m_texturesPerSecondHistory.insert(texturesPerSecond); |
346 | 344 |
347 m_availableQueries.append(m_pendingQueries.takeFirst()); | 345 m_availableQueries.append(m_pendingQueries.takeFirst()); |
348 } | 346 } |
349 } | 347 } |
350 | 348 |
351 } | 349 } |
OLD | NEW |