summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/BUILD.gn2
-rw-r--r--cc/cc.gyp1
-rw-r--r--cc/cc_tests.gyp1
-rw-r--r--cc/raster/pixel_buffer_tile_task_worker_pool.cc18
-rw-r--r--cc/raster/tile_task_worker_pool_unittest.cc4
-rw-r--r--cc/resources/resource.h33
-rw-r--r--cc/resources/resource_format.cc62
-rw-r--r--cc/resources/resource_format.h11
-rw-r--r--cc/resources/resource_pool.cc24
-rw-r--r--cc/resources/resource_pool_unittest.cc4
-rw-r--r--cc/resources/resource_provider.cc19
-rw-r--r--cc/resources/resource_provider.h55
-rw-r--r--cc/resources/resource_util.h242
-rw-r--r--cc/resources/resource_util_unittest.cc167
-rw-r--r--cc/resources/scoped_resource_unittest.cc6
-rw-r--r--cc/resources/video_resource_updater.cc18
-rw-r--r--cc/tiles/tile.cc4
-rw-r--r--cc/tiles/tile_manager.cc5
-rw-r--r--cc/tiles/tile_manager_unittest.cc4
19 files changed, 541 insertions, 139 deletions
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index e421db1..92e5917 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -394,6 +394,7 @@ component("cc") {
"resources/resource_pool.h",
"resources/resource_provider.cc",
"resources/resource_provider.h",
+ "resources/resource_util.h",
"resources/returned_resource.h",
"resources/scoped_resource.cc",
"resources/scoped_resource.h",
@@ -798,6 +799,7 @@ test("cc_unittests") {
"resources/platform_color_unittest.cc",
"resources/resource_pool_unittest.cc",
"resources/resource_provider_unittest.cc",
+ "resources/resource_util_unittest.cc",
"resources/scoped_resource_unittest.cc",
"resources/video_resource_updater_unittest.cc",
"scheduler/begin_frame_source_unittest.cc",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index af4c83d..a4c96465 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -451,6 +451,7 @@
'resources/resource_pool.h',
'resources/resource_provider.cc',
'resources/resource_provider.h',
+ 'resources/resource_util.h',
'resources/returned_resource.h',
'resources/scoped_resource.cc',
'resources/scoped_resource.h',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 5dfd42a..61ba1cf 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -97,6 +97,7 @@
'resources/platform_color_unittest.cc',
'resources/resource_pool_unittest.cc',
'resources/resource_provider_unittest.cc',
+ 'resources/resource_util_unittest.cc',
'resources/scoped_resource_unittest.cc',
'resources/video_resource_updater_unittest.cc',
'scheduler/begin_frame_source_unittest.cc',
diff --git a/cc/raster/pixel_buffer_tile_task_worker_pool.cc b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
index df79519..2d2524b 100644
--- a/cc/raster/pixel_buffer_tile_task_worker_pool.cc
+++ b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
@@ -436,9 +436,9 @@ void PixelBufferTileTaskWorkerPool::CheckForCompletedUploads() {
DCHECK(state_it != raster_task_states_.end());
RasterTaskState& state = *state_it;
- // We can use UncheckedMemorySizeBytes here, since these tasks come from
- // tiles, the size of which is controlled by the compositor.
- bytes_pending_upload_ -= Resource::UncheckedMemorySizeBytes(
+ // We can use UncheckedSizeInBytes here, since these tasks come from tiles,
+ // the size of which is controlled by the compositor.
+ bytes_pending_upload_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
task->resource()->size(), task->resource()->format());
task->WillComplete();
@@ -545,9 +545,9 @@ void PixelBufferTileTaskWorkerPool::ScheduleMoreTasks() {
// but if it's the only task allow it to complete no matter what its size,
// to prevent starvation of the task queue.
size_t new_bytes_pending_upload = bytes_pending_upload;
- // We can use UncheckedMemorySizeBytes here, since these tasks come from
- // tiles, the size of which is controlled by the compositor.
- new_bytes_pending_upload += Resource::UncheckedMemorySizeBytes(
+ // We can use UncheckedSizeInBytes here, since these tasks come from tiles,
+ // the size of which is controlled by the compositor.
+ new_bytes_pending_upload += ResourceUtil::UncheckedSizeInBytes<size_t>(
task->resource()->size(), task->resource()->format());
if (new_bytes_pending_upload > max_bytes_pending_upload_ &&
bytes_pending_upload) {
@@ -712,9 +712,9 @@ void PixelBufferTileTaskWorkerPool::CheckForCompletedRasterizerTasks() {
resource_provider_->BeginSetPixels(raster_task->resource()->id());
has_performed_uploads_since_last_flush_ = true;
- // We can use UncheckedMemorySizeBytes here, since these tasks come from
- // tiles, the size of which is controlled by the compositor.
- bytes_pending_upload_ += Resource::UncheckedMemorySizeBytes(
+ // We can use UncheckedSizeInBytes here, since these tasks come from tiles,
+ // the size of which is controlled by the compositor.
+ bytes_pending_upload_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
raster_task->resource()->size(), raster_task->resource()->format());
raster_tasks_with_pending_upload_.push_back(raster_task);
state.type = RasterTaskState::UPLOADING;
diff --git a/cc/raster/tile_task_worker_pool_unittest.cc b/cc/raster/tile_task_worker_pool_unittest.cc
index 76e5fe4..fa36474 100644
--- a/cc/raster/tile_task_worker_pool_unittest.cc
+++ b/cc/raster/tile_task_worker_pool_unittest.cc
@@ -406,8 +406,8 @@ TEST_P(TileTaskWorkerPoolTest, LargeResources) {
ScopedResource::Create(resource_provider_.get()));
resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
- EXPECT_GE(Resource::UncheckedMemorySizeBytes(resource->size(),
- resource->format()),
+ EXPECT_GE(ResourceUtil::UncheckedSizeInBytes<size_t>(resource->size(),
+ resource->format()),
kMaxTransferBufferUsageBytes);
}
diff --git a/cc/resources/resource.h b/cc/resources/resource.h
index f9138fb..549a314 100644
--- a/cc/resources/resource.h
+++ b/cc/resources/resource.h
@@ -5,9 +5,9 @@
#ifndef CC_RESOURCES_RESOURCE_H_
#define CC_RESOURCES_RESOURCE_H_
-#include "base/numerics/safe_math.h"
#include "cc/base/cc_export.h"
#include "cc/resources/resource_provider.h"
+#include "cc/resources/resource_util.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
@@ -24,37 +24,6 @@ class CC_EXPORT Resource {
gfx::Size size() const { return size_; }
ResourceFormat format() const { return format_; }
- // Return true if the call to UncheckedMemorySizeBytes would return a value
- // that fits in a size_t.
- static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format) {
- base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format);
- checked_value *= size.width();
- checked_value *= size.height();
- if (!checked_value.IsValid())
- return false;
- size_t value = checked_value.ValueOrDie();
- if ((value % 8) != 0)
- return false;
- return true;
- }
-
- static size_t CheckedMemorySizeBytes(const gfx::Size& size,
- ResourceFormat format) {
- DCHECK(VerifySizeInBytes(size, format));
- base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format);
- checked_value *= size.width();
- checked_value *= size.height();
- checked_value /= 8;
- return checked_value.ValueOrDie();
- }
-
- inline static size_t UncheckedMemorySizeBytes(const gfx::Size& size,
- ResourceFormat format) {
- DCHECK(VerifySizeInBytes(size, format));
- return static_cast<size_t>(BitsPerPixel(format)) * size.width() *
- size.height() / 8;
- }
-
protected:
void set_id(ResourceId id) { id_ = id; }
void set_dimensions(const gfx::Size& size, ResourceFormat format) {
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc
index 45581b8..ce9fe7d 100644
--- a/cc/resources/resource_format.cc
+++ b/cc/resources/resource_format.cc
@@ -4,6 +4,9 @@
#include "cc/resources/resource_format.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+
namespace cc {
SkColorType ResourceFormatToSkColorType(ResourceFormat format) {
@@ -25,4 +28,63 @@ SkColorType ResourceFormatToSkColorType(ResourceFormat format) {
return kN32_SkColorType;
}
+int BitsPerPixel(ResourceFormat format) {
+ switch (format) {
+ case BGRA_8888:
+ case RGBA_8888:
+ return 32;
+ case RGBA_4444:
+ case RGB_565:
+ return 16;
+ case ALPHA_8:
+ case LUMINANCE_8:
+ case RED_8:
+ return 8;
+ case ETC1:
+ return 4;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+GLenum GLDataType(ResourceFormat format) {
+ DCHECK_LE(format, RESOURCE_FORMAT_MAX);
+ static const GLenum format_gl_data_type[] = {
+ GL_UNSIGNED_BYTE, // RGBA_8888
+ GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
+ GL_UNSIGNED_BYTE, // BGRA_8888
+ GL_UNSIGNED_BYTE, // ALPHA_8
+ GL_UNSIGNED_BYTE, // LUMINANCE_8
+ GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
+ GL_UNSIGNED_BYTE, // ETC1
+ GL_UNSIGNED_BYTE // RED_8
+ };
+ static_assert(arraysize(format_gl_data_type) == (RESOURCE_FORMAT_MAX + 1),
+ "format_gl_data_type does not handle all cases.");
+
+ return format_gl_data_type[format];
+}
+
+GLenum GLDataFormat(ResourceFormat format) {
+ DCHECK_LE(format, RESOURCE_FORMAT_MAX);
+ static const GLenum format_gl_data_format[] = {
+ GL_RGBA, // RGBA_8888
+ GL_RGBA, // RGBA_4444
+ GL_BGRA_EXT, // BGRA_8888
+ GL_ALPHA, // ALPHA_8
+ GL_LUMINANCE, // LUMINANCE_8
+ GL_RGB, // RGB_565
+ GL_ETC1_RGB8_OES, // ETC1
+ GL_RED_EXT // RED_8
+ };
+ static_assert(arraysize(format_gl_data_format) == (RESOURCE_FORMAT_MAX + 1),
+ "format_gl_data_format does not handle all cases.");
+
+ return format_gl_data_format[format];
+}
+
+GLenum GLInternalFormat(ResourceFormat format) {
+ return GLDataFormat(format);
+}
+
} // namespace cc
diff --git a/cc/resources/resource_format.h b/cc/resources/resource_format.h
index d785ab7..d910bb0 100644
--- a/cc/resources/resource_format.h
+++ b/cc/resources/resource_format.h
@@ -6,8 +6,14 @@
#define CC_RESOURCES_RESOURCE_FORMAT_H_
#include "base/logging.h"
+#include "cc/base/cc_export.h"
#include "third_party/skia/include/core/SkBitmap.h"
+// TODO(prashant.n): Including third_party/khronos/GLES2/gl2.h causes
+// redefinition errors as macros/functions defined in it conflict with
+// macros/functions defined in ui/gl/gl_bindings.h. (http://crbug.com/512833).
+typedef unsigned int GLenum;
+
namespace cc {
// Keep in sync with arrays below.
@@ -25,6 +31,11 @@ enum ResourceFormat {
SkColorType ResourceFormatToSkColorType(ResourceFormat format);
+CC_EXPORT int BitsPerPixel(ResourceFormat format);
+CC_EXPORT GLenum GLDataType(ResourceFormat format);
+CC_EXPORT GLenum GLDataFormat(ResourceFormat format);
+CC_EXPORT GLenum GLInternalFormat(ResourceFormat format);
+
} // namespace cc
#endif // CC_RESOURCES_RESOURCE_FORMAT_H_
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 7b65d34..300c48f 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -5,6 +5,7 @@
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
+#include "cc/resources/resource_util.h"
#include "cc/resources/scoped_resource.h"
namespace cc {
@@ -48,7 +49,7 @@ scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
unused_resources_.erase(it);
unused_memory_usage_bytes_ -=
- Resource::UncheckedMemorySizeBytes(size, format);
+ ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
return make_scoped_ptr(resource);
}
@@ -56,9 +57,10 @@ scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
ScopedResource::Create(resource_provider_);
resource->AllocateManaged(size, target_, format);
- DCHECK(Resource::VerifySizeInBytes(resource->size(), resource->format()));
- memory_usage_bytes_ +=
- Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
+ DCHECK(ResourceUtil::VerifySizeInBytes<size_t>(resource->size(),
+ resource->format()));
+ memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
+ resource->size(), resource->format());
++resource_count_;
return resource.Pass();
}
@@ -78,8 +80,8 @@ scoped_ptr<ScopedResource> ResourcePool::TryAcquireResourceWithContentId(
DCHECK(resource_provider_->CanLockForWrite(resource->id()));
unused_resources_.erase(it);
- unused_memory_usage_bytes_ -=
- Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
+ unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
+ resource->size(), resource->format());
return make_scoped_ptr(resource);
}
@@ -112,7 +114,7 @@ void ResourcePool::ReduceResourceUsage() {
// memory is necessarily returned to the OS.
ScopedResource* resource = unused_resources_.front().resource;
unused_resources_.pop_front();
- unused_memory_usage_bytes_ -= Resource::UncheckedMemorySizeBytes(
+ unused_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
resource->size(), resource->format());
DeleteResource(resource);
}
@@ -129,8 +131,8 @@ bool ResourcePool::ResourceUsageTooHigh() {
}
void ResourcePool::DeleteResource(ScopedResource* resource) {
- size_t resource_bytes =
- Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
+ size_t resource_bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+ resource->size(), resource->format());
memory_usage_bytes_ -= resource_bytes;
--resource_count_;
delete resource;
@@ -160,8 +162,8 @@ void ResourcePool::CheckBusyResources(bool wait_if_needed) {
void ResourcePool::DidFinishUsingResource(ScopedResource* resource,
uint64_t content_id) {
- unused_memory_usage_bytes_ +=
- Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
+ unused_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
+ resource->size(), resource->format());
unused_resources_.push_back(PoolResource(resource, content_id));
}
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index 96e7591..035b19e 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/resources/resource_pool.h"
+#include "cc/resources/resource_util.h"
#include "cc/resources/scoped_resource.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
@@ -54,7 +55,8 @@ TEST_F(ResourcePoolTest, AccountingSingleResource) {
gfx::Size size(100, 100);
ResourceFormat format = RGBA_8888;
- size_t resource_bytes = Resource::UncheckedMemorySizeBytes(size, format);
+ size_t resource_bytes =
+ ResourceUtil::UncheckedSizeInBytes<size_t>(size, format);
scoped_ptr<ScopedResource> resource =
resource_pool_->AcquireResource(size, format);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 9f68066..30f3391f 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -14,8 +14,8 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/trace_event/trace_event.h"
-#include "cc/base/math_util.h"
#include "cc/resources/platform_color.h"
+#include "cc/resources/resource_util.h"
#include "cc/resources/returned_resource.h"
#include "cc/resources/shared_bitmap_manager.h"
#include "cc/resources/transferable_resource.h"
@@ -724,13 +724,10 @@ void ResourceProvider::CopyToResource(ResourceId id,
gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
if (resource->format == ETC1) {
- base::CheckedNumeric<int> num_bytes = BitsPerPixel(ETC1);
- num_bytes *= image_size.width();
- num_bytes *= image_size.height();
- num_bytes /= 8;
+ int image_bytes = ResourceUtil::CheckedSizeInBytes<int>(image_size, ETC1);
gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
image_size.width(), image_size.height(), 0,
- num_bytes.ValueOrDie(), image);
+ image_bytes, image);
} else {
gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
image_size.height(), GLDataFormat(resource->format),
@@ -1531,12 +1528,10 @@ void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
resource->gl_pixel_buffer_id);
- unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
- gl->BufferData(
- GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->size.height() *
- MathUtil::RoundUp(bytes_per_pixel * resource->size.width(), 4u),
- NULL, GL_DYNAMIC_DRAW);
+ size_t resource_bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
+ resource->size, resource->format);
+ gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, resource_bytes, NULL,
+ GL_DYNAMIC_DRAW);
gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index fbed140..44d555a 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -608,61 +608,6 @@ class CC_EXPORT ResourceProvider {
DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
};
-// TODO(epenner): Move these format conversions to resource_format.h
-// once that builds on mac (npapi.h currently #includes OpenGL.h).
-inline int BitsPerPixel(ResourceFormat format) {
- switch (format) {
- case BGRA_8888:
- case RGBA_8888:
- return 32;
- case RGBA_4444:
- case RGB_565:
- return 16;
- case ALPHA_8:
- case LUMINANCE_8:
- case RED_8:
- return 8;
- case ETC1:
- return 4;
- }
- NOTREACHED();
- return 0;
-}
-
-inline GLenum GLDataType(ResourceFormat format) {
- DCHECK_LE(format, RESOURCE_FORMAT_MAX);
- static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
- GL_UNSIGNED_BYTE, // RGBA_8888
- GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444
- GL_UNSIGNED_BYTE, // BGRA_8888
- GL_UNSIGNED_BYTE, // ALPHA_8
- GL_UNSIGNED_BYTE, // LUMINANCE_8
- GL_UNSIGNED_SHORT_5_6_5, // RGB_565,
- GL_UNSIGNED_BYTE, // ETC1
- GL_UNSIGNED_BYTE // RED_8
- };
- return format_gl_data_type[format];
-}
-
-inline GLenum GLDataFormat(ResourceFormat format) {
- DCHECK_LE(format, RESOURCE_FORMAT_MAX);
- static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
- GL_RGBA, // RGBA_8888
- GL_RGBA, // RGBA_4444
- GL_BGRA_EXT, // BGRA_8888
- GL_ALPHA, // ALPHA_8
- GL_LUMINANCE, // LUMINANCE_8
- GL_RGB, // RGB_565
- GL_ETC1_RGB8_OES, // ETC1
- GL_RED_EXT // RED_8
- };
- return format_gl_data_format[format];
-}
-
-inline GLenum GLInternalFormat(ResourceFormat format) {
- return GLDataFormat(format);
-}
-
} // namespace cc
#endif // CC_RESOURCES_RESOURCE_PROVIDER_H_
diff --git a/cc/resources/resource_util.h b/cc/resources/resource_util.h
new file mode 100644
index 0000000..0953fbb
--- /dev/null
+++ b/cc/resources/resource_util.h
@@ -0,0 +1,242 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_RESOURCE_UTIL_H_
+#define CC_RESOURCES_RESOURCE_UTIL_H_
+
+#include <limits>
+
+#include "base/numerics/safe_math.h"
+#include "cc/base/cc_export.h"
+#include "cc/base/math_util.h"
+#include "cc/resources/resource_format.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+
+class CC_EXPORT ResourceUtil {
+ public:
+ // Returns true if the width is valid and fits in bytes, false otherwise.
+ template <typename T>
+ static bool VerifyWidthInBytes(int width, ResourceFormat format);
+ // Returns true if the size is valid and fits in bytes, false otherwise.
+ template <typename T>
+ static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format);
+
+ // Dies with a CRASH() if the width can not be represented as a positive
+ // number of bytes.
+ template <typename T>
+ static T CheckedWidthInBytes(int width, ResourceFormat format);
+ // Dies with a CRASH() if the size can not be represented as a positive
+ // number of bytes.
+ template <typename T>
+ static T CheckedSizeInBytes(const gfx::Size& size, ResourceFormat format);
+
+ // Returns the width in bytes but may overflow or return 0. Only do this for
+ // computing widths for sizes that have already been checked.
+ template <typename T>
+ static T UncheckedWidthInBytes(int width, ResourceFormat format);
+ // Returns the size in bytes but may overflow or return 0. Only do this for
+ // sizes that have already been checked.
+ template <typename T>
+ static T UncheckedSizeInBytes(const gfx::Size& size, ResourceFormat format);
+ // Returns the width in bytes aligned but may overflow or return 0. Only do
+ // this for computing widths for sizes that have already been checked.
+ template <typename T>
+ static T UncheckedWidthInBytesAligned(int width, ResourceFormat format);
+ // Returns the size in bytes aligned but may overflow or return 0. Only do
+ // this for sizes that have already been checked.
+ template <typename T>
+ static T UncheckedSizeInBytesAligned(const gfx::Size& size,
+ ResourceFormat format);
+
+ private:
+ // TODO(prashant.n): Replace IsSameType with std::is_same once C++11 is used
+ // on all platforms.
+ template <typename T, typename U>
+ struct IsSameType {
+ static const bool value = false;
+ };
+
+ template <typename T>
+ struct IsSameType<T, T> {
+ static const bool value = true;
+ };
+
+ template <typename T>
+ static inline void VerifyType();
+
+ template <typename T>
+ static bool VerifyRoundUp(T value, T round_up);
+
+ template <typename T>
+ static bool VerifyFitsInBytesInternal(int width,
+ int height,
+ ResourceFormat format,
+ bool verify_size,
+ bool aligned);
+
+ template <typename T>
+ static T BytesInternal(int width,
+ int height,
+ ResourceFormat format,
+ bool verify_size,
+ bool aligned);
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceUtil);
+};
+
+template <typename T>
+bool ResourceUtil::VerifyWidthInBytes(int width, ResourceFormat format) {
+ VerifyType<T>();
+ return VerifyFitsInBytesInternal<T>(width, 0, format, false, false);
+}
+
+template <typename T>
+bool ResourceUtil::VerifySizeInBytes(const gfx::Size& size,
+ ResourceFormat format) {
+ VerifyType<T>();
+ return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+ false);
+}
+
+template <typename T>
+T ResourceUtil::CheckedWidthInBytes(int width, ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
+ base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+ checked_value *= width;
+ // TODO(prashant.n): Move the value roundup overflow to MathUtil class.
+ // http://crbug.com/515566
+ CHECK(VerifyRoundUp(checked_value.ValueOrDie(), static_cast<T>(8)));
+ checked_value = MathUtil::RoundUp<T>(checked_value.ValueOrDie(), 8);
+ checked_value /= 8;
+ return checked_value.ValueOrDie();
+}
+
+template <typename T>
+T ResourceUtil::CheckedSizeInBytes(const gfx::Size& size,
+ ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+ false));
+ base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+ checked_value *= size.width();
+ CHECK(VerifyRoundUp(checked_value.ValueOrDie(), static_cast<T>(8)));
+ checked_value = MathUtil::RoundUp<T>(checked_value.ValueOrDie(), 8);
+ checked_value /= 8;
+ checked_value *= size.height();
+ return checked_value.ValueOrDie();
+}
+
+template <typename T>
+T ResourceUtil::UncheckedWidthInBytes(int width, ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false));
+ return BytesInternal<T>(width, 0, format, false, false);
+}
+
+template <typename T>
+T ResourceUtil::UncheckedSizeInBytes(const gfx::Size& size,
+ ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+ false));
+ return BytesInternal<T>(size.width(), size.height(), format, true, false);
+}
+
+template <typename T>
+T ResourceUtil::UncheckedWidthInBytesAligned(int width, ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true));
+ return BytesInternal<T>(width, 0, format, false, true);
+}
+
+template <typename T>
+T ResourceUtil::UncheckedSizeInBytesAligned(const gfx::Size& size,
+ ResourceFormat format) {
+ VerifyType<T>();
+ DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true,
+ true));
+ return BytesInternal<T>(size.width(), size.height(), format, true, true);
+}
+
+template <typename T>
+void ResourceUtil::VerifyType() {
+ static_assert(
+ std::numeric_limits<T>::is_integer && !IsSameType<T, bool>::value,
+ "T must be non-bool integer type. Preferred type is size_t.");
+}
+
+template <typename T>
+bool ResourceUtil::VerifyRoundUp(T value, T round_up) {
+ if (round_up == 0)
+ return false;
+ if (value == round_up)
+ return true;
+ if ((std::numeric_limits<T>::max() - (value - (value % round_up))) >=
+ round_up)
+ return true;
+ return false;
+}
+
+template <typename T>
+bool ResourceUtil::VerifyFitsInBytesInternal(int width,
+ int height,
+ ResourceFormat format,
+ bool verify_size,
+ bool aligned) {
+ base::CheckedNumeric<T> checked_value = BitsPerPixel(format);
+ checked_value *= width;
+ if (!checked_value.IsValid())
+ return false;
+
+ // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is
+ // 4, then it should return 16, so that row pixels do not get truncated.
+ DCHECK(VerifyRoundUp(checked_value.ValueOrDie(), static_cast<T>(8)));
+ checked_value = MathUtil::RoundUp<T>(checked_value.ValueOrDie(), 8);
+
+ // If aligned is true, bytes are aligned on 4-bytes boundaries for upload
+ // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have
+ // not changed from default.
+ if (aligned) {
+ checked_value /= 8;
+ if (!checked_value.IsValid())
+ return false;
+ checked_value = MathUtil::RoundUp<T>(checked_value.ValueOrDie(), 4);
+ checked_value *= 8;
+ }
+
+ if (verify_size)
+ checked_value *= height;
+ if (!checked_value.IsValid())
+ return false;
+ T value = checked_value.ValueOrDie();
+ if ((value % 8) != 0)
+ return false;
+ return true;
+}
+
+template <typename T>
+T ResourceUtil::BytesInternal(int width,
+ int height,
+ ResourceFormat format,
+ bool verify_size,
+ bool aligned) {
+ T bytes = BitsPerPixel(format);
+ bytes *= width;
+ DCHECK(VerifyRoundUp(bytes, static_cast<T>(8)));
+ bytes = MathUtil::RoundUp<T>(bytes, 8);
+ bytes /= 8;
+ if (aligned)
+ bytes = MathUtil::RoundUp<T>(bytes, 4);
+ if (verify_size)
+ bytes *= height;
+
+ return bytes;
+}
+
+} // namespace cc
+
+#endif // CC_RESOURCES_RESOURCE_UTIL_H_
diff --git a/cc/resources/resource_util_unittest.cc b/cc/resources/resource_util_unittest.cc
new file mode 100644
index 0000000..1fabc3b
--- /dev/null
+++ b/cc/resources/resource_util_unittest.cc
@@ -0,0 +1,167 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "cc/resources/resource_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+struct TestFormat {
+ ResourceFormat format;
+ size_t expected_bytes;
+ size_t expected_bytes_aligned;
+};
+
+// Modify this constant as per TestFormat variables defined in following tests.
+const int kTestFormats = 4;
+
+class ResourceUtilTest : public testing::Test {
+ public:
+ void TestVerifyWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ EXPECT_TRUE(ResourceUtil::VerifyWidthInBytes<size_t>(
+ width, test_formats[i].format));
+ }
+ }
+
+ void TestCheckedWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::CheckedWidthInBytes<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::UncheckedWidthInBytes<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedWidthInBytesAligned(int width,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::UncheckedWidthInBytesAligned<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
+ }
+ }
+
+ void TestVerifySizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<size_t>(
+ size, test_formats[i].format));
+ }
+ }
+
+ void TestCheckedSizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::CheckedSizeInBytes<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedSizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::UncheckedSizeInBytes<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedSizeInBytesAligned(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceUtil::UncheckedSizeInBytesAligned<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
+ }
+ }
+};
+
+TEST_F(ResourceUtilTest, WidthInBytes) {
+ // Check bytes for even width.
+ int width = 10;
+ TestFormat test_formats[] = {
+ {RGBA_8888, 40, 40}, // for 32 bits
+ {RGBA_4444, 20, 20}, // for 16 bits
+ {ALPHA_8, 10, 12}, // for 8 bits
+ {ETC1, 5, 8} // for 4 bits
+ };
+
+ TestVerifyWidthInBytes(width, test_formats);
+ TestCheckedWidthInBytes(width, test_formats);
+ TestUncheckedWidthInBytes(width, test_formats);
+ TestUncheckedWidthInBytesAligned(width, test_formats);
+
+ // Check bytes for odd width.
+ int width_odd = 11;
+ TestFormat test_formats_odd[] = {
+ {RGBA_8888, 44, 44}, // for 32 bits
+ {RGBA_4444, 22, 24}, // for 16 bits
+ {ALPHA_8, 11, 12}, // for 8 bits
+ {ETC1, 6, 8} // for 4 bits
+ };
+
+ TestVerifyWidthInBytes(width_odd, test_formats_odd);
+ TestCheckedWidthInBytes(width_odd, test_formats_odd);
+ TestUncheckedWidthInBytes(width_odd, test_formats_odd);
+ TestUncheckedWidthInBytesAligned(width_odd, test_formats_odd);
+}
+
+TEST_F(ResourceUtilTest, SizeInBytes) {
+ // Check bytes for even size.
+ gfx::Size size(10, 10);
+ TestFormat test_formats[] = {
+ {RGBA_8888, 400, 400}, // for 32 bits
+ {RGBA_4444, 200, 200}, // for 16 bits
+ {ALPHA_8, 100, 120}, // for 8 bits
+ {ETC1, 50, 80} // for 4 bits
+ };
+
+ TestVerifySizeInBytes(size, test_formats);
+ TestCheckedSizeInBytes(size, test_formats);
+ TestUncheckedSizeInBytes(size, test_formats);
+ TestUncheckedSizeInBytesAligned(size, test_formats);
+
+ // Check bytes for odd size.
+ gfx::Size size_odd(11, 11);
+ TestFormat test_formats_odd[] = {
+ {RGBA_8888, 484, 484}, // for 32 bits
+ {RGBA_4444, 242, 264}, // for 16 bits
+ {ALPHA_8, 121, 132}, // for 8 bits
+ {ETC1, 66, 88} // for 4 bits
+ };
+
+ TestVerifySizeInBytes(size_odd, test_formats_odd);
+ TestCheckedSizeInBytes(size_odd, test_formats_odd);
+ TestUncheckedSizeInBytes(size_odd, test_formats_odd);
+ TestUncheckedSizeInBytesAligned(size_odd, test_formats_odd);
+}
+
+TEST_F(ResourceUtilTest, WidthInBytesOverflow) {
+ int width = 10;
+ // 10 * 16 = 160 bits, overflows in char, but fits in unsigned char.
+ EXPECT_FALSE(ResourceUtil::VerifyWidthInBytes<signed char>(width, RGBA_4444));
+ EXPECT_TRUE(
+ ResourceUtil::VerifyWidthInBytes<unsigned char>(width, RGBA_4444));
+}
+
+TEST_F(ResourceUtilTest, SizeInBytesOverflow) {
+ gfx::Size size(10, 10);
+ // 10 * 16 * 10 = 1600 bits, overflows in char, but fits in int.
+ EXPECT_FALSE(ResourceUtil::VerifySizeInBytes<signed char>(size, RGBA_4444));
+ EXPECT_TRUE(ResourceUtil::VerifySizeInBytes<int>(size, RGBA_4444));
+}
+
+} // namespace
+} // namespace cc
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index 197fa1f3..cb41bf6 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -31,8 +31,8 @@ TEST(ScopedResourceTest, NewScopedResource) {
// New scoped textures do not have a size yet.
EXPECT_EQ(gfx::Size(), texture->size());
- EXPECT_EQ(0u, Resource::UncheckedMemorySizeBytes(texture->size(),
- texture->format()));
+ EXPECT_EQ(0u, ResourceUtil::UncheckedSizeInBytes<size_t>(texture->size(),
+ texture->format()));
}
TEST(ScopedResourceTest, CreateScopedResource) {
@@ -51,7 +51,7 @@ TEST(ScopedResourceTest, CreateScopedResource) {
// The texture has an allocated byte-size now.
size_t expected_bytes = 30 * 30 * 4;
- EXPECT_EQ(expected_bytes, Resource::UncheckedMemorySizeBytes(
+ EXPECT_EQ(expected_bytes, ResourceUtil::UncheckedSizeInBytes<size_t>(
texture->size(), texture->format()));
EXPECT_LT(0u, texture->id());
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index dd5606e..88e8360 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -305,16 +305,18 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
gfx::Size resource_size_pixels = plane_resource.resource_size;
// The |video_stride_pixels| is the width of the video frame we are
// uploading (including non-frame data to fill in the stride).
- size_t video_stride_pixels = video_frame->stride(i);
+ int video_stride_pixels = video_frame->stride(i);
- size_t bytes_per_pixel = BitsPerPixel(plane_resource.resource_format) / 8;
+ size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>(
+ resource_size_pixels.width(), plane_resource.resource_format);
// Use 4-byte row alignment (OpenGL default) for upload performance.
// Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
- size_t upload_image_stride = MathUtil::RoundUp<size_t>(
- bytes_per_pixel * resource_size_pixels.width(), 4u);
+ size_t upload_image_stride = MathUtil::RoundUp<size_t>(bytes_per_row, 4u);
const uint8_t* pixels;
- if (upload_image_stride == video_stride_pixels * bytes_per_pixel) {
+ size_t video_bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>(
+ video_stride_pixels, plane_resource.resource_format);
+ if (upload_image_stride == video_bytes_per_row) {
pixels = video_frame->data(i);
} else {
// Avoid malloc for each frame/plane if possible.
@@ -324,9 +326,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
upload_pixels_.resize(needed_size);
for (int row = 0; row < resource_size_pixels.height(); ++row) {
uint8_t* dst = &upload_pixels_[upload_image_stride * row];
- const uint8_t* src = video_frame->data(i) +
- bytes_per_pixel * video_stride_pixels * row;
- memcpy(dst, src, resource_size_pixels.width() * bytes_per_pixel);
+ const uint8_t* src =
+ video_frame->data(i) + (video_bytes_per_row * row);
+ memcpy(dst, src, bytes_per_row);
}
pixels = &upload_pixels_[0];
}
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index 6052e5e..ad50dd1 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -71,8 +71,8 @@ size_t Tile::GPUMemoryUsageInBytes() const {
if (draw_info_.resource_) {
// We can use UncheckedSizeInBytes, since the tile size is determined by the
// compositor.
- return Resource::UncheckedMemorySizeBytes(draw_info_.resource_->size(),
- draw_info_.resource_->format());
+ return ResourceUtil::UncheckedSizeInBytes<size_t>(
+ draw_info_.resource_->size(), draw_info_.resource_->format());
}
return 0;
}
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 23d2eca..545866e 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -1045,9 +1045,10 @@ TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
const gfx::Size& size,
ResourceFormat format) {
- // We can use UncheckedMemorySizeBytes here since this is used with a tile
+ // We can use UncheckedSizeInBytes here since this is used with a tile
// size which is determined by the compositor (it's at most max texture size).
- return MemoryUsage(Resource::UncheckedMemorySizeBytes(size, format), 1);
+ return MemoryUsage(ResourceUtil::UncheckedSizeInBytes<size_t>(size, format),
+ 1);
}
// static
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 891d082..27ef65d 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -1386,8 +1386,8 @@ TEST_F(TileManagerTilePriorityQueueTest,
EXPECT_EQ(RGBA_8888, host_impl_.resource_provider()->best_texture_format());
ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy();
- policy.bytes_limit_when_visible =
- Resource::UncheckedMemorySizeBytes(gfx::Size(256, 256), RGBA_8888);
+ policy.bytes_limit_when_visible = ResourceUtil::UncheckedSizeInBytes<size_t>(
+ gfx::Size(256, 256), RGBA_8888);
host_impl_.SetMemoryPolicy(policy);
EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());