diff options
author | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-17 21:51:06 +0000 |
---|---|---|
committer | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-17 21:51:06 +0000 |
commit | 373c09e1076f3a77e61ef46c97b4a01b74965049 (patch) | |
tree | 22919cbe89daf4110fda47caa0e3226b0f007102 | |
parent | a5069b572223392930fb1f619cd9d9103eb103da (diff) | |
download | chromium_src-373c09e1076f3a77e61ef46c97b4a01b74965049.zip chromium_src-373c09e1076f3a77e61ef46c97b4a01b74965049.tar.gz chromium_src-373c09e1076f3a77e61ef46c97b4a01b74965049.tar.bz2 |
cc: Chromify TextureUploader
R=danakj@chromium.org
BUG=none
Review URL: https://chromiumcodereview.appspot.com/12589009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188655 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/resource_provider.cc | 14 | ||||
-rw-r--r-- | cc/texture_uploader.cc | 544 | ||||
-rw-r--r-- | cc/texture_uploader.h | 183 | ||||
-rw-r--r-- | cc/texture_uploader_unittest.cc | 380 |
4 files changed, 555 insertions, 566 deletions
diff --git a/cc/resource_provider.cc b/cc/resource_provider.cc index cb3c634..092a3b3 100644 --- a/cc/resource_provider.cc +++ b/cc/resource_provider.cc @@ -354,7 +354,7 @@ void ResourceProvider::SetPixels(ResourceId id, DCHECK(context3d); DCHECK(texture_uploader_.get()); context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id); - texture_uploader_->upload(image, + texture_uploader_->Upload(image, image_rect, source_rect, dest_offset, @@ -387,35 +387,35 @@ size_t ResourceProvider::NumBlockingUploads() { if (!texture_uploader_) return 0; - return texture_uploader_->numBlockingUploads(); + return texture_uploader_->NumBlockingUploads(); } void ResourceProvider::MarkPendingUploadsAsNonBlocking() { if (!texture_uploader_) return; - texture_uploader_->markPendingUploadsAsNonBlocking(); + texture_uploader_->MarkPendingUploadsAsNonBlocking(); } double ResourceProvider::EstimatedUploadsPerSecond() { if (!texture_uploader_) return 0.0; - return texture_uploader_->estimatedTexturesPerSecond(); + return texture_uploader_->EstimatedTexturesPerSecond(); } void ResourceProvider::FlushUploads() { if (!texture_uploader_) return; - texture_uploader_->flush(); + texture_uploader_->Flush(); } void ResourceProvider::ReleaseCachedData() { if (!texture_uploader_) return; - texture_uploader_->releaseCachedQueries(); + texture_uploader_->ReleaseCachedQueries(); } void ResourceProvider::Flush() { @@ -635,7 +635,7 @@ bool ResourceProvider::Initialize() { AcceleratedTextureCopier::Create(context3d, use_bind_uniform); texture_uploader_ = - TextureUploader::create(context3d, use_map_sub, use_shallow_flush_); + TextureUploader::Create(context3d, use_map_sub, use_shallow_flush_); GLC(context3d, context3d->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_)); best_texture_format_ = diff --git a/cc/texture_uploader.cc b/cc/texture_uploader.cc index 8414a5f..95f6096 100644 --- a/cc/texture_uploader.cc +++ b/cc/texture_uploader.cc @@ -23,357 +23,329 @@ namespace { // How many previous uploads to use when predicting future throughput. -static const size_t uploadHistorySizeMax = 1000; -static const size_t uploadHistorySizeInitial = 100; +static const size_t kUploadHistorySizeMax = 1000; +static const size_t kUploadHistorySizeInitial = 100; // Global estimated number of textures per second to maintain estimates across // subsequent instances of TextureUploader. -// More than one thread will not access this variable, so we do not need to synchronize access. -static const double defaultEstimatedTexturesPerSecond = 48.0 * 60.0; +// More than one thread will not access this variable, so we do not need to +// synchronize access. +static const double kDefaultEstimatedTexturesPerSecond = 48.0 * 60.0; // Flush interval when performing texture uploads. -const int textureUploadFlushPeriod = 4; +static const int kTextureUploadFlushPeriod = 4; -} // anonymous namespace +} // anonymous namespace namespace cc { TextureUploader::Query::Query(WebKit::WebGraphicsContext3D* context) - : m_context(context) - , m_queryId(0) - , m_value(0) - , m_hasValue(false) - , m_isNonBlocking(false) -{ - m_queryId = m_context->createQueryEXT(); + : context_(context), + query_id_(0), + value_(0), + has_value_(false), + is_non_blocking_(false) { + query_id_ = context_->createQueryEXT(); } -TextureUploader::Query::~Query() -{ - m_context->deleteQueryEXT(m_queryId); -} - -void TextureUploader::Query::begin() -{ - m_hasValue = false; - m_isNonBlocking = false; - m_context->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, m_queryId); -} - -void TextureUploader::Query::end() -{ - m_context->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); -} +TextureUploader::Query::~Query() { context_->deleteQueryEXT(query_id_); } -bool TextureUploader::Query::isPending() -{ - unsigned available = 1; - m_context->getQueryObjectuivEXT(m_queryId, GL_QUERY_RESULT_AVAILABLE_EXT, &available); - return !available; +void TextureUploader::Query::Begin() { + has_value_ = false; + is_non_blocking_ = false; + context_->beginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM, query_id_); } -unsigned TextureUploader::Query::value() -{ - if (!m_hasValue) { - m_context->getQueryObjectuivEXT(m_queryId, GL_QUERY_RESULT_EXT, &m_value); - m_hasValue = true; - } - return m_value; +void TextureUploader::Query::End() { + context_->endQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM); } -void TextureUploader::Query::markAsNonBlocking() -{ - m_isNonBlocking = true; +bool TextureUploader::Query::IsPending() { + unsigned available = 1; + context_->getQueryObjectuivEXT( + query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available); + return !available; } -bool TextureUploader::Query::isNonBlocking() -{ - return m_isNonBlocking; +unsigned TextureUploader::Query::Value() { + if (!has_value_) { + context_->getQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &value_); + has_value_ = true; + } + return value_; } -TextureUploader::TextureUploader( - WebKit::WebGraphicsContext3D* context, - bool useMapTexSubImage, - bool useShallowFlush) - : m_context(context) - , m_numBlockingTextureUploads(0) - , m_useMapTexSubImage(useMapTexSubImage) - , m_subImageSize(0) - , m_useShallowFlush(useShallowFlush) - , m_numTextureUploadsSinceLastFlush(0) -{ - for (size_t i = uploadHistorySizeInitial; i > 0; i--) - m_texturesPerSecondHistory.insert(defaultEstimatedTexturesPerSecond); +TextureUploader::TextureUploader(WebKit::WebGraphicsContext3D* context, + bool use_map_tex_sub_image, + bool useShallowFlush) + : context_(context), + num_blocking_texture_uploads_(0), + use_map_tex_sub_image_(use_map_tex_sub_image), + sub_image_size_(0), + use_shallow_flush_(useShallowFlush), + num_texture_uploads_since_last_flush_(0) { + for (size_t i = kUploadHistorySizeInitial; i > 0; i--) + textures_per_second_history_.insert(kDefaultEstimatedTexturesPerSecond); } -TextureUploader::~TextureUploader() -{ -} +TextureUploader::~TextureUploader() {} -size_t TextureUploader::numBlockingUploads() -{ - processQueries(); - return m_numBlockingTextureUploads; +size_t TextureUploader::NumBlockingUploads() { + ProcessQueries(); + return num_blocking_texture_uploads_; } -void TextureUploader::markPendingUploadsAsNonBlocking() -{ - for (ScopedPtrDeque<Query>::iterator it = m_pendingQueries.begin(); - it != m_pendingQueries.end(); ++it) { - if ((*it)->isNonBlocking()) - continue; +void TextureUploader::MarkPendingUploadsAsNonBlocking() { + for (ScopedPtrDeque<Query>::iterator it = pending_queries_.begin(); + it != pending_queries_.end(); + ++it) { + if ((*it)->is_non_blocking()) + continue; - m_numBlockingTextureUploads--; - (*it)->markAsNonBlocking(); - } + num_blocking_texture_uploads_--; + (*it)->mark_as_non_blocking(); + } - DCHECK(!m_numBlockingTextureUploads); + DCHECK(!num_blocking_texture_uploads_); } -double TextureUploader::estimatedTexturesPerSecond() -{ - processQueries(); +double TextureUploader::EstimatedTexturesPerSecond() { + ProcessQueries(); - // Use the median as our estimate. - std::multiset<double>::iterator median = m_texturesPerSecondHistory.begin(); - std::advance(median, m_texturesPerSecondHistory.size() / 2); - TRACE_COUNTER_ID1("cc", "EstimatedTexturesPerSecond", m_context, *median); - return *median; + // Use the median as our estimate. + std::multiset<double>::iterator median = textures_per_second_history_.begin(); + std::advance(median, textures_per_second_history_.size() / 2); + TRACE_COUNTER_ID1("cc", "EstimatedTexturesPerSecond", context_, *median); + return *median; } -void TextureUploader::beginQuery() -{ - if (m_availableQueries.empty()) - m_availableQueries.push_back(Query::create(m_context)); +void TextureUploader::BeginQuery() { + if (available_queries_.empty()) + available_queries_.push_back(Query::Create(context_)); - m_availableQueries.front()->begin(); + available_queries_.front()->Begin(); } -void TextureUploader::endQuery() -{ - m_availableQueries.front()->end(); - m_pendingQueries.push_back(m_availableQueries.take_front()); - m_numBlockingTextureUploads++; +void TextureUploader::EndQuery() { + available_queries_.front()->End(); + pending_queries_.push_back(available_queries_.take_front()); + num_blocking_texture_uploads_++; } -void TextureUploader::upload(const uint8* image, - const gfx::Rect& image_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, +void TextureUploader::Upload(const uint8* image, + gfx::Rect image_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, GLenum format, - const gfx::Size& size) -{ - CHECK(image_rect.Contains(source_rect)); + gfx::Size size) { + CHECK(image_rect.Contains(source_rect)); - bool isFullUpload = dest_offset.IsZero() && source_rect.size() == size; + bool is_full_upload = dest_offset.IsZero() && source_rect.size() == size; - if (isFullUpload) - beginQuery(); + if (is_full_upload) + BeginQuery(); - if (m_useMapTexSubImage) { - uploadWithMapTexSubImage( - image, image_rect, source_rect, dest_offset, format); - } else { - uploadWithTexSubImage( - image, image_rect, source_rect, dest_offset, format); - } + if (use_map_tex_sub_image_) { + UploadWithMapTexSubImage( + image, image_rect, source_rect, dest_offset, format); + } else { + UploadWithTexSubImage(image, image_rect, source_rect, dest_offset, format); + } - if (isFullUpload) - endQuery(); + if (is_full_upload) + EndQuery(); - m_numTextureUploadsSinceLastFlush++; - if (m_numTextureUploadsSinceLastFlush >= textureUploadFlushPeriod) - flush(); + num_texture_uploads_since_last_flush_++; + if (num_texture_uploads_since_last_flush_ >= kTextureUploadFlushPeriod) + Flush(); } -void TextureUploader::flush() { - if (!m_numTextureUploadsSinceLastFlush) +void TextureUploader::Flush() { + if (!num_texture_uploads_since_last_flush_) return; - if (m_useShallowFlush) - m_context->shallowFlushCHROMIUM(); + if (use_shallow_flush_) + context_->shallowFlushCHROMIUM(); - m_numTextureUploadsSinceLastFlush = 0; + num_texture_uploads_since_last_flush_ = 0; } -void TextureUploader::releaseCachedQueries() -{ - processQueries(); - m_availableQueries.clear(); +void TextureUploader::ReleaseCachedQueries() { + ProcessQueries(); + available_queries_.clear(); } -void TextureUploader::uploadWithTexSubImage(const uint8* image, - const gfx::Rect& image_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - GLenum format) -{ - // Instrumentation to debug issue 156107 - int source_rect_x = source_rect.x(); - int source_rect_y = source_rect.y(); - int source_rect_width = source_rect.width(); - int source_rect_height = source_rect.height(); - int image_rect_x = image_rect.x(); - int image_rect_y = image_rect.y(); - int image_rect_width = image_rect.width(); - int image_rect_height = image_rect.height(); - int dest_offset_x = dest_offset.x(); - int dest_offset_y = dest_offset.y(); - base::debug::Alias(&image); - base::debug::Alias(&source_rect_x); - base::debug::Alias(&source_rect_y); - base::debug::Alias(&source_rect_width); - base::debug::Alias(&source_rect_height); - base::debug::Alias(&image_rect_x); - base::debug::Alias(&image_rect_y); - base::debug::Alias(&image_rect_width); - base::debug::Alias(&image_rect_height); - base::debug::Alias(&dest_offset_x); - base::debug::Alias(&dest_offset_y); - TRACE_EVENT0("cc", "TextureUploader::uploadWithTexSubImage"); - - // Offset from image-rect to source-rect. - gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); - - const uint8* pixel_source; - unsigned int bytes_per_pixel = Resource::BytesPerPixel(format); - // Use 4-byte row alignment (OpenGL default) for upload performance. - // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. - unsigned int upload_image_stride = - RoundUp(bytes_per_pixel * source_rect.width(), 4u); - - if (upload_image_stride == image_rect.width() * bytes_per_pixel && !offset.x()) { - pixel_source = &image[image_rect.width() * bytes_per_pixel * offset.y()]; - } else { - size_t needed_size = upload_image_stride * source_rect.height(); - if (m_subImageSize < needed_size) { - m_subImage.reset(new uint8[needed_size]); - m_subImageSize = needed_size; - } - // Strides not equal, so do a row-by-row memcpy from the - // paint results into a temp buffer for uploading. - for (int row = 0; row < source_rect.height(); ++row) - memcpy(&m_subImage[upload_image_stride * row], - &image[bytes_per_pixel * (offset.x() + - (offset.y() + row) * image_rect.width())], - source_rect.width() * bytes_per_pixel); - - pixel_source = &m_subImage[0]; +void TextureUploader::UploadWithTexSubImage(const uint8* image, + gfx::Rect image_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, + GLenum format) { + // Instrumentation to debug issue 156107 + int source_rect_x = source_rect.x(); + int source_rect_y = source_rect.y(); + int source_rect_width = source_rect.width(); + int source_rect_height = source_rect.height(); + int image_rect_x = image_rect.x(); + int image_rect_y = image_rect.y(); + int image_rect_width = image_rect.width(); + int image_rect_height = image_rect.height(); + int dest_offset_x = dest_offset.x(); + int dest_offset_y = dest_offset.y(); + base::debug::Alias(&image); + base::debug::Alias(&source_rect_x); + base::debug::Alias(&source_rect_y); + base::debug::Alias(&source_rect_width); + base::debug::Alias(&source_rect_height); + base::debug::Alias(&image_rect_x); + base::debug::Alias(&image_rect_y); + base::debug::Alias(&image_rect_width); + base::debug::Alias(&image_rect_height); + base::debug::Alias(&dest_offset_x); + base::debug::Alias(&dest_offset_y); + TRACE_EVENT0("cc", "TextureUploader::uploadWithTexSubImage"); + + // Offset from image-rect to source-rect. + gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); + + const uint8* pixel_source; + unsigned int bytes_per_pixel = Resource::BytesPerPixel(format); + // Use 4-byte row alignment (OpenGL default) for upload performance. + // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. + unsigned int upload_image_stride = + RoundUp(bytes_per_pixel * source_rect.width(), 4u); + + if (upload_image_stride == image_rect.width() * bytes_per_pixel && + !offset.x()) { + pixel_source = &image[image_rect.width() * bytes_per_pixel * offset.y()]; + } else { + size_t needed_size = upload_image_stride * source_rect.height(); + if (sub_image_size_ < needed_size) { + sub_image_.reset(new uint8[needed_size]); + sub_image_size_ = needed_size; } - - m_context->texSubImage2D(GL_TEXTURE_2D, - 0, - dest_offset.x(), - dest_offset.y(), - source_rect.width(), - source_rect.height(), - format, - GL_UNSIGNED_BYTE, - pixel_source); + // Strides not equal, so do a row-by-row memcpy from the + // paint results into a temp buffer for uploading. + for (int row = 0; row < source_rect.height(); ++row) + memcpy(&sub_image_[upload_image_stride * row], + &image[bytes_per_pixel * + (offset.x() + (offset.y() + row) * image_rect.width())], + source_rect.width() * bytes_per_pixel); + + pixel_source = &sub_image_[0]; + } + + context_->texSubImage2D(GL_TEXTURE_2D, + 0, + dest_offset.x(), + dest_offset.y(), + source_rect.width(), + source_rect.height(), + format, + GL_UNSIGNED_BYTE, + pixel_source); } -void TextureUploader::uploadWithMapTexSubImage(const uint8* image, - const gfx::Rect& image_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - GLenum format) -{ - // Instrumentation to debug issue 156107 - int source_rect_x = source_rect.x(); - int source_rect_y = source_rect.y(); - int source_rect_width = source_rect.width(); - int source_rect_height = source_rect.height(); - int image_rect_x = image_rect.x(); - int image_rect_y = image_rect.y(); - int image_rect_width = image_rect.width(); - int image_rect_height = image_rect.height(); - int dest_offset_x = dest_offset.x(); - int dest_offset_y = dest_offset.y(); - base::debug::Alias(&image); - base::debug::Alias(&source_rect_x); - base::debug::Alias(&source_rect_y); - base::debug::Alias(&source_rect_width); - base::debug::Alias(&source_rect_height); - base::debug::Alias(&image_rect_x); - base::debug::Alias(&image_rect_y); - base::debug::Alias(&image_rect_width); - base::debug::Alias(&image_rect_height); - base::debug::Alias(&dest_offset_x); - base::debug::Alias(&dest_offset_y); - - TRACE_EVENT0("cc", "TextureUploader::uploadWithMapTexSubImage"); - - // Offset from image-rect to source-rect. - gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); - - unsigned int bytes_per_pixel = Resource::BytesPerPixel(format); - // Use 4-byte row alignment (OpenGL default) for upload performance. - // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. - unsigned int upload_image_stride = - RoundUp(bytes_per_pixel * source_rect.width(), 4u); - - // Upload tile data via a mapped transfer buffer - uint8* pixel_dest = static_cast<uint8*>( - m_context->mapTexSubImage2DCHROMIUM(GL_TEXTURE_2D, - 0, - dest_offset.x(), - dest_offset.y(), - source_rect.width(), - source_rect.height(), - format, - GL_UNSIGNED_BYTE, - GL_WRITE_ONLY)); - - if (!pixel_dest) { - uploadWithTexSubImage( - image, image_rect, source_rect, dest_offset, format); - return; - } - - if (upload_image_stride == image_rect.width() * bytes_per_pixel && !offset.x()) { - memcpy(pixel_dest, - &image[image_rect.width() * bytes_per_pixel * offset.y()], - source_rect.height() * image_rect.width() * bytes_per_pixel); - } else { - // Strides not equal, so do a row-by-row memcpy from the - // paint results into the pixelDest - for (int row = 0; row < source_rect.height(); ++row) - memcpy(&pixel_dest[upload_image_stride * row], - &image[bytes_per_pixel * (offset.x() + - (offset.y() + row) * image_rect.width())], - source_rect.width() * bytes_per_pixel); +void TextureUploader::UploadWithMapTexSubImage(const uint8* image, + gfx::Rect image_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, + GLenum format) { + // Instrumentation to debug issue 156107 + int source_rect_x = source_rect.x(); + int source_rect_y = source_rect.y(); + int source_rect_width = source_rect.width(); + int source_rect_height = source_rect.height(); + int image_rect_x = image_rect.x(); + int image_rect_y = image_rect.y(); + int image_rect_width = image_rect.width(); + int image_rect_height = image_rect.height(); + int dest_offset_x = dest_offset.x(); + int dest_offset_y = dest_offset.y(); + base::debug::Alias(&image); + base::debug::Alias(&source_rect_x); + base::debug::Alias(&source_rect_y); + base::debug::Alias(&source_rect_width); + base::debug::Alias(&source_rect_height); + base::debug::Alias(&image_rect_x); + base::debug::Alias(&image_rect_y); + base::debug::Alias(&image_rect_width); + base::debug::Alias(&image_rect_height); + base::debug::Alias(&dest_offset_x); + base::debug::Alias(&dest_offset_y); + + TRACE_EVENT0("cc", "TextureUploader::uploadWithMapTexSubImage"); + + // Offset from image-rect to source-rect. + gfx::Vector2d offset(source_rect.origin() - image_rect.origin()); + + unsigned int bytes_per_pixel = Resource::BytesPerPixel(format); + // Use 4-byte row alignment (OpenGL default) for upload performance. + // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. + unsigned int upload_image_stride = + RoundUp(bytes_per_pixel * source_rect.width(), 4u); + + // Upload tile data via a mapped transfer buffer + uint8* pixel_dest = static_cast<uint8*>( + context_->mapTexSubImage2DCHROMIUM(GL_TEXTURE_2D, + 0, + dest_offset.x(), + dest_offset.y(), + source_rect.width(), + source_rect.height(), + format, + GL_UNSIGNED_BYTE, + GL_WRITE_ONLY)); + + if (!pixel_dest) { + UploadWithTexSubImage(image, image_rect, source_rect, dest_offset, format); + return; + } + + if (upload_image_stride == image_rect.width() * bytes_per_pixel && + !offset.x()) { + memcpy(pixel_dest, + &image[image_rect.width() * bytes_per_pixel * offset.y()], + source_rect.height() * image_rect.width() * bytes_per_pixel); + } else { + // Strides not equal, so do a row-by-row memcpy from the + // paint results into the pixelDest + for (int row = 0; row < source_rect.height(); ++row) { + memcpy(&pixel_dest[upload_image_stride * row], + &image[bytes_per_pixel * + (offset.x() + (offset.y() + row) * image_rect.width())], + source_rect.width() * bytes_per_pixel); } + } - m_context->unmapTexSubImage2DCHROMIUM(pixel_dest); + context_->unmapTexSubImage2DCHROMIUM(pixel_dest); } -void TextureUploader::processQueries() -{ - while (!m_pendingQueries.empty()) { - if (m_pendingQueries.front()->isPending()) - break; - - unsigned usElapsed = m_pendingQueries.front()->value(); - UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.TextureGpuUploadTimeUS", - usElapsed, 0, 100000, 50); +void TextureUploader::ProcessQueries() { + while (!pending_queries_.empty()) { + if (pending_queries_.front()->IsPending()) + break; - // Clamp the queries to saner values in case the queries fail. - usElapsed = std::max(1u, usElapsed); - usElapsed = std::min(15000u, usElapsed); + unsigned us_elapsed = pending_queries_.front()->Value(); + UMA_HISTOGRAM_CUSTOM_COUNTS( + "Renderer4.TextureGpuUploadTimeUS", us_elapsed, 0, 100000, 50); - if (!m_pendingQueries.front()->isNonBlocking()) - m_numBlockingTextureUploads--; + // Clamp the queries to saner values in case the queries fail. + us_elapsed = std::max(1u, us_elapsed); + us_elapsed = std::min(15000u, us_elapsed); - // Remove the min and max value from our history and insert the new one. - double texturesPerSecond = 1.0 / (usElapsed * 1e-6); - if (m_texturesPerSecondHistory.size() >= uploadHistorySizeMax) { - m_texturesPerSecondHistory.erase(m_texturesPerSecondHistory.begin()); - m_texturesPerSecondHistory.erase(--m_texturesPerSecondHistory.end()); - } - m_texturesPerSecondHistory.insert(texturesPerSecond); + if (!pending_queries_.front()->is_non_blocking()) + num_blocking_texture_uploads_--; - m_availableQueries.push_back(m_pendingQueries.take_front()); + // Remove the min and max value from our history and insert the new one. + double textures_per_second = 1.0 / (us_elapsed * 1e-6); + if (textures_per_second_history_.size() >= kUploadHistorySizeMax) { + textures_per_second_history_.erase(textures_per_second_history_.begin()); + textures_per_second_history_.erase(--textures_per_second_history_.end()); } + textures_per_second_history_.insert(textures_per_second); + + available_queries_.push_back(pending_queries_.take_front()); + } } } // namespace cc diff --git a/cc/texture_uploader.h b/cc/texture_uploader.h index d4acf8d..44f67f8 100644 --- a/cc/texture_uploader.h +++ b/cc/texture_uploader.h @@ -13,9 +13,7 @@ #include "cc/scoped_ptr_deque.h" #include "third_party/khronos/GLES2/gl2.h" -namespace WebKit { -class WebGraphicsContext3D; -} +namespace WebKit { class WebGraphicsContext3D; } namespace gfx { class Rect; @@ -26,93 +24,100 @@ class Vector2d; namespace cc { class CC_EXPORT TextureUploader { -public: - static scoped_ptr<TextureUploader> create( - WebKit::WebGraphicsContext3D* context, - bool useMapTexSubImage, - bool useShallowFlush) - { - return make_scoped_ptr( - new TextureUploader(context, useMapTexSubImage, useShallowFlush)); + public: + static scoped_ptr<TextureUploader> Create( + WebKit::WebGraphicsContext3D* context, + bool use_map_tex_sub_image, + bool use_shallow_flush) { + return make_scoped_ptr( + new TextureUploader(context, use_map_tex_sub_image, use_shallow_flush)); + } + ~TextureUploader(); + + size_t NumBlockingUploads(); + void MarkPendingUploadsAsNonBlocking(); + double EstimatedTexturesPerSecond(); + + // Let content_rect be a rectangle, and let content_rect be a sub-rectangle of + // content_rect, expressed in the same coordinate system as content_rect. Let + // image be a buffer for content_rect. This function will copy the region + // corresponding to sourceRect to destOffset in this sub-image. + void Upload(const uint8* image, + gfx::Rect content_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, + GLenum format, + gfx::Size size); + + void Flush(); + void ReleaseCachedQueries(); + + private: + class Query { + public: + static scoped_ptr<Query> Create(WebKit::WebGraphicsContext3D* context) { + return make_scoped_ptr(new Query(context)); + } + + virtual ~Query(); + + void Begin(); + void End(); + bool IsPending(); + unsigned Value(); + size_t TexturesUploaded(); + void mark_as_non_blocking() { + is_non_blocking_ = true; + } + bool is_non_blocking() const { + return is_non_blocking_; } - ~TextureUploader(); - - size_t numBlockingUploads(); - void markPendingUploadsAsNonBlocking(); - double estimatedTexturesPerSecond(); - - // Let imageRect be a rectangle, and let sourceRect be a sub-rectangle of - // imageRect, expressed in the same coordinate system as imageRect. Let - // image be a buffer for imageRect. This function will copy the region - // corresponding to sourceRect to destOffset in this sub-image. - void upload(const uint8* image, - const gfx::Rect& content_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - GLenum format, - const gfx::Size& size); - - void flush(); - void releaseCachedQueries(); - -private: - class Query { - public: - static scoped_ptr<Query> create(WebKit::WebGraphicsContext3D* context) { return make_scoped_ptr(new Query(context)); } - - virtual ~Query(); - - void begin(); - void end(); - bool isPending(); - unsigned value(); - size_t texturesUploaded(); - void markAsNonBlocking(); - bool isNonBlocking(); - - private: - explicit Query(WebKit::WebGraphicsContext3D*); - - WebKit::WebGraphicsContext3D* m_context; - unsigned m_queryId; - unsigned m_value; - bool m_hasValue; - bool m_isNonBlocking; - }; - - TextureUploader(WebKit::WebGraphicsContext3D*, - bool useMapTexSubImage, - bool useShallowFlush); - - void beginQuery(); - void endQuery(); - void processQueries(); - - void uploadWithTexSubImage(const uint8* image, - const gfx::Rect& image_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - GLenum format); - void uploadWithMapTexSubImage(const uint8* image, - const gfx::Rect& image_rect, - const gfx::Rect& source_rect, - const gfx::Vector2d& dest_offset, - GLenum format); - - WebKit::WebGraphicsContext3D* m_context; - ScopedPtrDeque<Query> m_pendingQueries; - ScopedPtrDeque<Query> m_availableQueries; - std::multiset<double> m_texturesPerSecondHistory; - size_t m_numBlockingTextureUploads; - - bool m_useMapTexSubImage; - size_t m_subImageSize; - scoped_array<uint8> m_subImage; - - bool m_useShallowFlush; - size_t m_numTextureUploadsSinceLastFlush; - - DISALLOW_COPY_AND_ASSIGN(TextureUploader); + + private: + explicit Query(WebKit::WebGraphicsContext3D* context); + + WebKit::WebGraphicsContext3D* context_; + unsigned query_id_; + unsigned value_; + bool has_value_; + bool is_non_blocking_; + + DISALLOW_COPY_AND_ASSIGN(Query); + }; + + TextureUploader(WebKit::WebGraphicsContext3D* context, + bool use_map_tex_sub_image, + bool use_shallow_flush); + + void BeginQuery(); + void EndQuery(); + void ProcessQueries(); + + void UploadWithTexSubImage(const uint8* image, + gfx::Rect image_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, + GLenum format); + void UploadWithMapTexSubImage(const uint8* image, + gfx::Rect image_rect, + gfx::Rect source_rect, + gfx::Vector2d dest_offset, + GLenum format); + + WebKit::WebGraphicsContext3D* context_; + ScopedPtrDeque<Query> pending_queries_; + ScopedPtrDeque<Query> available_queries_; + std::multiset<double> textures_per_second_history_; + size_t num_blocking_texture_uploads_; + + bool use_map_tex_sub_image_; + size_t sub_image_size_; + scoped_array<uint8> sub_image_; + + bool use_shallow_flush_; + size_t num_texture_uploads_since_last_flush_; + + DISALLOW_COPY_AND_ASSIGN(TextureUploader); }; } // namespace cc diff --git a/cc/texture_uploader_unittest.cc b/cc/texture_uploader_unittest.cc index 4e95628..69e6c8b 100644 --- a/cc/texture_uploader_unittest.cc +++ b/cc/texture_uploader_unittest.cc @@ -6,6 +6,7 @@ #include "cc/prioritized_resource.h" #include "cc/test/test_web_graphics_context_3d.h" +#include "cc/util.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/khronos/GLES2/gl2.h" @@ -16,215 +17,226 @@ using namespace WebKit; namespace cc { namespace { -unsigned int RoundUp(unsigned int n, unsigned int mul) -{ - return (((n - 1) / mul) * mul) + mul; -} - class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D { -public: - TestWebGraphicsContext3DTextureUpload() - : m_resultAvailable(0) - , m_unpackAlignment(4) - { - } - - virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) - { - switch (pname) { - case GL_UNPACK_ALIGNMENT: - // param should be a power of two <= 8 - EXPECT_EQ(0, param & (param - 1)); - EXPECT_GE(8, param); - switch (param) { - case 1: - case 2: - case 4: - case 8: - m_unpackAlignment = param; - break; - default: - break; - } + public: + TestWebGraphicsContext3DTextureUpload() + : result_available_(0), + unpack_alignment_(4) {} + + virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) OVERRIDE { + switch (pname) { + case GL_UNPACK_ALIGNMENT: + // Param should be a power of two <= 8. + EXPECT_EQ(0, param & (param - 1)); + EXPECT_GE(8, param); + switch (param) { + case 1: + case 2: + case 4: + case 8: + unpack_alignment_ = param; break; - default: + default: break; } + break; + default: + break; } - - virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value) - { + } + + virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value) + OVERRIDE { + switch (type) { + case GL_QUERY_RESULT_AVAILABLE_EXT: + *value = result_available_; + break; + default: + *value = 0; + break; + } + } + + virtual void texSubImage2D(WGC3Denum target, + WGC3Dint level, + WGC3Dint xoffset, + WGC3Dint yoffset, + WGC3Dsizei width, + WGC3Dsizei height, + WGC3Denum format, + WGC3Denum type, + const void* pixels) OVERRIDE { + EXPECT_EQ(GL_TEXTURE_2D, target); + EXPECT_EQ(0, level); + EXPECT_LE(0, width); + EXPECT_LE(0, height); + EXPECT_LE(0, xoffset); + EXPECT_LE(0, yoffset); + EXPECT_LE(0, width); + EXPECT_LE(0, height); + + // Check for allowed format/type combination. + unsigned int bytes_per_pixel = 0; + switch (format) { + case GL_ALPHA: + EXPECT_EQ(GL_UNSIGNED_BYTE, type); + bytes_per_pixel = 1; + break; + case GL_RGB: + EXPECT_NE(GL_UNSIGNED_SHORT_4_4_4_4, type); + EXPECT_NE(GL_UNSIGNED_SHORT_5_5_5_1, type); switch (type) { - case GL_QUERY_RESULT_AVAILABLE_EXT: - *value = m_resultAvailable; + case GL_UNSIGNED_BYTE: + bytes_per_pixel = 3; break; - default: - *value = 0; + case GL_UNSIGNED_SHORT_5_6_5: + bytes_per_pixel = 2; break; } - } - - virtual void texSubImage2D(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format, WGC3Denum type, const void* pixels) - { - EXPECT_EQ(GL_TEXTURE_2D, target); - EXPECT_EQ(0, level); - EXPECT_LE(0, width); - EXPECT_LE(0, height); - EXPECT_LE(0, xoffset); - EXPECT_LE(0, yoffset); - EXPECT_LE(0, width); - EXPECT_LE(0, height); - - // Check for allowed format/type combination. - unsigned int bytesPerPixel = 0; - switch (format) { - case GL_ALPHA: - EXPECT_EQ(GL_UNSIGNED_BYTE, type); - bytesPerPixel = 1; - break; - case GL_RGB: - EXPECT_NE(GL_UNSIGNED_SHORT_4_4_4_4, type); - EXPECT_NE(GL_UNSIGNED_SHORT_5_5_5_1, type); - switch (type) { - case GL_UNSIGNED_BYTE: - bytesPerPixel = 3; - break; - case GL_UNSIGNED_SHORT_5_6_5: - bytesPerPixel = 2; - break; - } - break; - case GL_RGBA: - EXPECT_NE(GL_UNSIGNED_SHORT_5_6_5, type); - switch (type) { - case GL_UNSIGNED_BYTE: - bytesPerPixel = 4; - break; - case GL_UNSIGNED_SHORT_4_4_4_4: - bytesPerPixel = 2; - break; - case GL_UNSIGNED_SHORT_5_5_5_1: - bytesPerPixel = 2; - break; - } + break; + case GL_RGBA: + EXPECT_NE(GL_UNSIGNED_SHORT_5_6_5, type); + switch (type) { + case GL_UNSIGNED_BYTE: + bytes_per_pixel = 4; break; - case GL_LUMINANCE: - EXPECT_EQ(GL_UNSIGNED_BYTE, type); - bytesPerPixel = 1; + case GL_UNSIGNED_SHORT_4_4_4_4: + bytes_per_pixel = 2; break; - case GL_LUMINANCE_ALPHA: - EXPECT_EQ(GL_UNSIGNED_BYTE, type); - bytesPerPixel = 2; + case GL_UNSIGNED_SHORT_5_5_5_1: + bytes_per_pixel = 2; break; } + break; + case GL_LUMINANCE: + EXPECT_EQ(GL_UNSIGNED_BYTE, type); + bytes_per_pixel = 1; + break; + case GL_LUMINANCE_ALPHA: + EXPECT_EQ(GL_UNSIGNED_BYTE, type); + bytes_per_pixel = 2; + break; + } - // If NULL, we aren't checking texture contents. - if (pixels == NULL) - return; - - const uint8* bytes = static_cast<const uint8*>(pixels); - // We'll expect the first byte of every row to be 0x1, and the last byte to be 0x2 - const unsigned int stride = RoundUp(bytesPerPixel * width, m_unpackAlignment); - for (WGC3Dsizei row = 0; row < height; ++row) { - const uint8* rowBytes = bytes + (xoffset * bytesPerPixel + (yoffset + row) * stride); - EXPECT_EQ(0x1, rowBytes[0]); - EXPECT_EQ(0x2, rowBytes[width * bytesPerPixel - 1]); - } + // If NULL, we aren't checking texture contents. + if (pixels == NULL) + return; + + const uint8* bytes = static_cast<const uint8*>(pixels); + // We'll expect the first byte of every row to be 0x1, and the last byte to + // be 0x2. + const unsigned int stride = + RoundUp(bytes_per_pixel * width, unpack_alignment_); + for (WGC3Dsizei row = 0; row < height; ++row) { + const uint8* row_bytes = + bytes + (xoffset * bytes_per_pixel + (yoffset + row) * stride); + EXPECT_EQ(0x1, row_bytes[0]); + EXPECT_EQ(0x2, row_bytes[width * bytes_per_pixel - 1]); } + } - void setResultAvailable(unsigned resultAvailable) { m_resultAvailable = resultAvailable; } + void SetResultAvailable(unsigned result_available) { + result_available_ = result_available; + } -private: - unsigned m_unpackAlignment; - unsigned m_resultAvailable; + private: + unsigned unpack_alignment_; + unsigned result_available_; + + DISALLOW_COPY_AND_ASSIGN(TestWebGraphicsContext3DTextureUpload); }; -void uploadTexture(TextureUploader* uploader, WGC3Denum format, const gfx::Size& size, const uint8* data) -{ - uploader->upload(data, - gfx::Rect(gfx::Point(0, 0), size), - gfx::Rect(gfx::Point(0, 0), size), - gfx::Vector2d(), - format, - size); +void UploadTexture(TextureUploader* uploader, + WGC3Denum format, + gfx::Size size, + const uint8* data) { + uploader->Upload(data, + gfx::Rect(gfx::Point(), size), + gfx::Rect(gfx::Point(), size), + gfx::Vector2d(), + format, + size); } -TEST(TextureUploaderTest, NumBlockingUploads) -{ - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fakeContext(new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = TextureUploader::create(fakeContext.get(), false, false); - - fakeContext->setResultAvailable(0); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(1, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(2, uploader->numBlockingUploads()); - - fakeContext->setResultAvailable(1); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(0, uploader->numBlockingUploads()); +TEST(TextureUploaderTest, NumBlockingUploads) { + scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( + new TestWebGraphicsContext3DTextureUpload); + scoped_ptr<TextureUploader> uploader = + TextureUploader::Create(fake_context.get(), false, false); + + fake_context->SetResultAvailable(0); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(1, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(2, uploader->NumBlockingUploads()); + + fake_context->SetResultAvailable(1); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(0, uploader->NumBlockingUploads()); } -TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) -{ - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fakeContext(new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = TextureUploader::create(fakeContext.get(), false, false); - - fakeContext->setResultAvailable(0); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(2, uploader->numBlockingUploads()); - - uploader->markPendingUploadsAsNonBlocking(); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - EXPECT_EQ(1, uploader->numBlockingUploads()); - - fakeContext->setResultAvailable(1); - EXPECT_EQ(0, uploader->numBlockingUploads()); - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(0, 0), NULL); - uploader->markPendingUploadsAsNonBlocking(); - EXPECT_EQ(0, uploader->numBlockingUploads()); +TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) { + scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( + new TestWebGraphicsContext3DTextureUpload); + scoped_ptr<TextureUploader> uploader = + TextureUploader::Create(fake_context.get(), false, false); + + fake_context->SetResultAvailable(0); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(2, uploader->NumBlockingUploads()); + + uploader->MarkPendingUploadsAsNonBlocking(); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + EXPECT_EQ(1, uploader->NumBlockingUploads()); + + fake_context->SetResultAvailable(1); + EXPECT_EQ(0, uploader->NumBlockingUploads()); + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL); + uploader->MarkPendingUploadsAsNonBlocking(); + EXPECT_EQ(0, uploader->NumBlockingUploads()); } -TEST(TextureUploaderTest, UploadContentsTest) -{ - scoped_ptr<TestWebGraphicsContext3DTextureUpload> fakeContext(new TestWebGraphicsContext3DTextureUpload); - scoped_ptr<TextureUploader> uploader = TextureUploader::create(fakeContext.get(), false, false); - uint8 buffer[256 * 256 * 4]; - - // Upload a tightly packed 256x256 RGBA texture. - memset(buffer, 0, sizeof(buffer)); - for (int i = 0; i < 256; ++i) { - // Mark the beginning and end of each row, for the test. - buffer[i * 4 * 256] = 0x1; - buffer[(i + 1) * 4 * 256 - 1] = 0x2; - } - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(256, 256), buffer); - - // Upload a tightly packed 41x43 RGBA texture. - memset(buffer, 0, sizeof(buffer)); - for (int i = 0; i < 43; ++i) { - // Mark the beginning and end of each row, for the test. - buffer[i * 4 * 41] = 0x1; - buffer[(i + 1) * 4 * 41 - 1] = 0x2; - } - uploadTexture(uploader.get(), GL_RGBA, gfx::Size(41, 43), buffer); - - // Upload a tightly packed 82x86 LUMINANCE texture. - memset(buffer, 0, sizeof(buffer)); - for (int i = 0; i < 86; ++i) { - // Mark the beginning and end of each row, for the test. - buffer[i * 1 * 82] = 0x1; - buffer[(i + 1) * 82 - 1] = 0x2; - } - uploadTexture(uploader.get(), GL_LUMINANCE, gfx::Size(82, 86), buffer); +TEST(TextureUploaderTest, UploadContentsTest) { + scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context( + new TestWebGraphicsContext3DTextureUpload); + scoped_ptr<TextureUploader> uploader = + TextureUploader::Create(fake_context.get(), false, false); + uint8 buffer[256 * 256 * 4]; + + // Upload a tightly packed 256x256 RGBA texture. + memset(buffer, 0, sizeof(buffer)); + for (int i = 0; i < 256; ++i) { + // Mark the beginning and end of each row, for the test. + buffer[i * 4 * 256] = 0x1; + buffer[(i + 1) * 4 * 256 - 1] = 0x2; + } + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(256, 256), buffer); + + // Upload a tightly packed 41x43 RGBA texture. + memset(buffer, 0, sizeof(buffer)); + for (int i = 0; i < 43; ++i) { + // Mark the beginning and end of each row, for the test. + buffer[i * 4 * 41] = 0x1; + buffer[(i + 1) * 4 * 41 - 1] = 0x2; + } + UploadTexture(uploader.get(), GL_RGBA, gfx::Size(41, 43), buffer); + + // Upload a tightly packed 82x86 LUMINANCE texture. + memset(buffer, 0, sizeof(buffer)); + for (int i = 0; i < 86; ++i) { + // Mark the beginning and end of each row, for the test. + buffer[i * 1 * 82] = 0x1; + buffer[(i + 1) * 82 - 1] = 0x2; + } + UploadTexture(uploader.get(), GL_LUMINANCE, gfx::Size(82, 86), buffer); } } // namespace |