Commit d880a3de authored by aelias's avatar aelias Committed by Commit bot

Restrict ETC1 power-of-two rounding to old IMG drivers.

The ETC1 spec says that any multiple of 4 is allowed for ETC1 size, but
certain old IMG devices (notably the Galaxy Nexus) crash unless the
textures are specifically power-of-two. To avoid wasting RAM on all
devices due to this device-specific problem, this patch plumbs a driver
workaround flag to the thumbnail store (the only user of ETC1 at
present).

We considered adding a workaround to the service side like all of the
others, but because texture size impacts memory budgeting and
coordinates, this one seems like it needs to be in the client code.

NOTRY=true
BUG=150500

Review URL: https://codereview.chromium.org/470233003

Cr-Commit-Position: refs/heads/master@{#291814}
parent 9ecb800c
...@@ -38,8 +38,6 @@ const int kCurrentExtraVersion = 1; ...@@ -38,8 +38,6 @@ const int kCurrentExtraVersion = 1;
// Indicates whether we prefer to have more free CPU memory over GPU memory. // Indicates whether we prefer to have more free CPU memory over GPU memory.
const bool kPreferCPUMemory = true; const bool kPreferCPUMemory = true;
// TODO(): ETC1 texture sizes should be multiples of four, but some drivers only
// allow power-of-two ETC1 textures. Find better work around.
size_t NextPowerOfTwo(size_t x) { size_t NextPowerOfTwo(size_t x) {
--x; --x;
x |= x >> 1; x |= x >> 1;
...@@ -50,10 +48,18 @@ size_t NextPowerOfTwo(size_t x) { ...@@ -50,10 +48,18 @@ size_t NextPowerOfTwo(size_t x) {
return x + 1; return x + 1;
} }
gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) { size_t RoundUpMod4(size_t x) {
return (x + 3) & ~3;
}
gfx::Size GetEncodedSize(const gfx::Size& bitmap_size, bool supports_npot) {
DCHECK(!bitmap_size.IsEmpty()); DCHECK(!bitmap_size.IsEmpty());
return gfx::Size(NextPowerOfTwo(bitmap_size.width()), if (!supports_npot)
NextPowerOfTwo(bitmap_size.height())); return gfx::Size(NextPowerOfTwo(bitmap_size.width()),
NextPowerOfTwo(bitmap_size.height()));
else
return gfx::Size(RoundUpMod4(bitmap_size.width()),
RoundUpMod4(bitmap_size.height()));
} }
template<typename T> template<typename T>
...@@ -365,11 +371,16 @@ void ThumbnailStore::CompressThumbnailIfNecessary( ...@@ -365,11 +371,16 @@ void ThumbnailStore::CompressThumbnailIfNecessary(
time_stamp, time_stamp,
scale); scale);
base::WorkerPool::PostTask( gfx::Size raw_data_size(bitmap.width(), bitmap.height());
FROM_HERE, gfx::Size encoded_size = GetEncodedSize(
base::Bind( raw_data_size, ui_resource_provider_->SupportsETC1NonPowerOfTwo());
&ThumbnailStore::CompressionTask, bitmap, post_compression_task),
true); base::WorkerPool::PostTask(FROM_HERE,
base::Bind(&ThumbnailStore::CompressionTask,
bitmap,
encoded_size,
post_compression_task),
true);
} }
void ThumbnailStore::ReadNextThumbnail() { void ThumbnailStore::ReadNextThumbnail() {
...@@ -539,6 +550,7 @@ void ThumbnailStore::PostWriteTask() { ...@@ -539,6 +550,7 @@ void ThumbnailStore::PostWriteTask() {
void ThumbnailStore::CompressionTask( void ThumbnailStore::CompressionTask(
SkBitmap raw_data, SkBitmap raw_data,
gfx::Size encoded_size,
const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>& const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>&
post_compression_task) { post_compression_task) {
skia::RefPtr<SkPixelRef> compressed_data; skia::RefPtr<SkPixelRef> compressed_data;
...@@ -550,7 +562,6 @@ void ThumbnailStore::CompressionTask( ...@@ -550,7 +562,6 @@ void ThumbnailStore::CompressionTask(
size_t pixel_size = 4; // Pixel size is 4 bytes for kARGB_8888_Config. size_t pixel_size = 4; // Pixel size is 4 bytes for kARGB_8888_Config.
size_t stride = pixel_size * raw_data_size.width(); size_t stride = pixel_size * raw_data_size.width();
gfx::Size encoded_size = GetEncodedSize(raw_data_size);
size_t encoded_bytes = size_t encoded_bytes =
etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height()); etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height());
SkImageInfo info = {encoded_size.width(), SkImageInfo info = {encoded_size.width(),
......
...@@ -110,6 +110,7 @@ class ThumbnailStore : ThumbnailDelegate { ...@@ -110,6 +110,7 @@ class ThumbnailStore : ThumbnailDelegate {
void PostWriteTask(); void PostWriteTask();
static void CompressionTask( static void CompressionTask(
SkBitmap raw_data, SkBitmap raw_data,
gfx::Size encoded_size,
const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>& const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>&
post_compression_task); post_compression_task);
void PostCompressionTask(TabId tab_id, void PostCompressionTask(TabId tab_id,
......
...@@ -63,6 +63,8 @@ class MockUIResourceProvider : public content::UIResourceProvider { ...@@ -63,6 +63,8 @@ class MockUIResourceProvider : public content::UIResourceProvider {
ui_resource_client_map_.erase(id); ui_resource_client_map_.erase(id);
} }
virtual bool SupportsETC1NonPowerOfTwo() const OVERRIDE { return true; }
void LayerTreeHostCleared() { void LayerTreeHostCleared() {
has_layer_tree_host_ = false; has_layer_tree_host_ = false;
UIResourceClientMap client_map = ui_resource_client_map_; UIResourceClientMap client_map = ui_resource_client_map_;
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
namespace content { namespace content {
UIResourceProviderImpl::UIResourceProviderImpl() UIResourceProviderImpl::UIResourceProviderImpl()
: system_ui_resource_manager_(this), host_(NULL) { : system_ui_resource_manager_(this), host_(NULL),
supports_etc1_npot_(false) {
} }
UIResourceProviderImpl::~UIResourceProviderImpl() { UIResourceProviderImpl::~UIResourceProviderImpl() {
...@@ -63,4 +65,8 @@ UIResourceProviderImpl::GetSystemUIResourceManager() { ...@@ -63,4 +65,8 @@ UIResourceProviderImpl::GetSystemUIResourceManager() {
return system_ui_resource_manager_; return system_ui_resource_manager_;
} }
bool UIResourceProviderImpl::SupportsETC1NonPowerOfTwo() const {
return supports_etc1_npot_;
}
} // namespace content } // namespace content
...@@ -34,12 +34,18 @@ class UIResourceProviderImpl : public UIResourceProvider { ...@@ -34,12 +34,18 @@ class UIResourceProviderImpl : public UIResourceProvider {
ui::SystemUIResourceManager& GetSystemUIResourceManager(); ui::SystemUIResourceManager& GetSystemUIResourceManager();
void SetSupportsETC1NonPowerOfTwo(bool supports_etc1_npot) {
supports_etc1_npot_ = supports_etc1_npot;
}
virtual bool SupportsETC1NonPowerOfTwo() const OVERRIDE;
private: private:
typedef base::hash_map<cc::UIResourceId, UIResourceClientAndroid*> typedef base::hash_map<cc::UIResourceId, UIResourceClientAndroid*>
UIResourceClientMap; UIResourceClientMap;
UIResourceClientMap ui_resource_client_map_; UIResourceClientMap ui_resource_client_map_;
SystemUIResourceManagerImpl system_ui_resource_manager_; SystemUIResourceManagerImpl system_ui_resource_manager_;
cc::LayerTreeHost* host_; cc::LayerTreeHost* host_;
bool supports_etc1_npot_;
DISALLOW_COPY_AND_ASSIGN(UIResourceProviderImpl); DISALLOW_COPY_AND_ASSIGN(UIResourceProviderImpl);
}; };
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/containers/hash_tables.h" #include "base/containers/hash_tables.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
...@@ -56,9 +57,12 @@ const unsigned int kMaxSwapBuffers = 2U; ...@@ -56,9 +57,12 @@ const unsigned int kMaxSwapBuffers = 2U;
class OutputSurfaceWithoutParent : public cc::OutputSurface { class OutputSurfaceWithoutParent : public cc::OutputSurface {
public: public:
OutputSurfaceWithoutParent(const scoped_refptr< OutputSurfaceWithoutParent(const scoped_refptr<
content::ContextProviderCommandBuffer>& context_provider) content::ContextProviderCommandBuffer>& context_provider,
base::WeakPtr<content::CompositorImpl> compositor_impl)
: cc::OutputSurface(context_provider) { : cc::OutputSurface(context_provider) {
capabilities_.adjust_deadline_for_parent = false; capabilities_.adjust_deadline_for_parent = false;
compositor_impl_ = compositor_impl;
main_thread_ = base::MessageLoopProxy::current();
} }
virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE { virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
...@@ -72,6 +76,22 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface { ...@@ -72,6 +76,22 @@ class OutputSurfaceWithoutParent : public cc::OutputSurface {
OutputSurface::SwapBuffers(frame); OutputSurface::SwapBuffers(frame);
} }
virtual bool BindToClient(cc::OutputSurfaceClient* client) OVERRIDE {
if (!OutputSurface::BindToClient(client))
return false;
main_thread_->PostTask(
FROM_HERE,
base::Bind(&content::CompositorImpl::PopulateGpuCapabilities,
compositor_impl_,
context_provider_->ContextCapabilities().gpu));
return true;
}
scoped_refptr<base::MessageLoopProxy> main_thread_;
base::WeakPtr<content::CompositorImpl> compositor_impl_;
}; };
class SurfaceTextureTrackerImpl : public gfx::SurfaceTextureTracker { class SurfaceTextureTrackerImpl : public gfx::SurfaceTextureTracker {
...@@ -552,8 +572,14 @@ scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface( ...@@ -552,8 +572,14 @@ scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
return scoped_ptr<cc::OutputSurface>(); return scoped_ptr<cc::OutputSurface>();
} }
return scoped_ptr<cc::OutputSurface>( return scoped_ptr<cc::OutputSurface>(new OutputSurfaceWithoutParent(
new OutputSurfaceWithoutParent(context_provider)); context_provider, weak_factory_.GetWeakPtr()));
}
void CompositorImpl::PopulateGpuCapabilities(
gpu::Capabilities gpu_capabilities) {
ui_resource_provider_.SetSupportsETC1NonPowerOfTwo(
gpu_capabilities.texture_format_etc1_npot);
} }
void CompositorImpl::OnLostResources() { void CompositorImpl::OnLostResources() {
......
...@@ -15,7 +15,9 @@ ...@@ -15,7 +15,9 @@
#include "content/browser/android/ui_resource_provider_impl.h" #include "content/browser/android/ui_resource_provider_impl.h"
#include "content/browser/renderer_host/image_transport_factory_android.h" #include "content/browser/renderer_host/image_transport_factory_android.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/public/browser/android/compositor.h" #include "content/public/browser/android/compositor.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "third_party/khronos/GLES2/gl2.h" #include "third_party/khronos/GLES2/gl2.h"
#include "ui/base/android/system_ui_resource_manager.h" #include "ui/base/android/system_ui_resource_manager.h"
#include "ui/base/android/window_android_compositor.h" #include "ui/base/android/window_android_compositor.h"
...@@ -54,6 +56,8 @@ class CONTENT_EXPORT CompositorImpl ...@@ -54,6 +56,8 @@ class CONTENT_EXPORT CompositorImpl
// Destroy all surface textures associated with |child_process_id|. // Destroy all surface textures associated with |child_process_id|.
static void DestroyAllSurfaceTextures(int child_process_id); static void DestroyAllSurfaceTextures(int child_process_id);
void PopulateGpuCapabilities(gpu::Capabilities gpu_capabilities);
private: private:
// Compositor implementation. // Compositor implementation.
virtual void SetRootLayer(scoped_refptr<cc::Layer> root) OVERRIDE; virtual void SetRootLayer(scoped_refptr<cc::Layer> root) OVERRIDE;
......
...@@ -194,6 +194,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities) ...@@ -194,6 +194,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities)
IPC_STRUCT_TRAITS_MEMBER(egl_image_external) IPC_STRUCT_TRAITS_MEMBER(egl_image_external)
IPC_STRUCT_TRAITS_MEMBER(texture_format_bgra8888) IPC_STRUCT_TRAITS_MEMBER(texture_format_bgra8888)
IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1) IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1)
IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1_npot)
IPC_STRUCT_TRAITS_MEMBER(texture_rectangle) IPC_STRUCT_TRAITS_MEMBER(texture_rectangle)
IPC_STRUCT_TRAITS_MEMBER(iosurface) IPC_STRUCT_TRAITS_MEMBER(iosurface)
IPC_STRUCT_TRAITS_MEMBER(texture_usage) IPC_STRUCT_TRAITS_MEMBER(texture_usage)
......
...@@ -20,6 +20,8 @@ class CONTENT_EXPORT UIResourceProvider { ...@@ -20,6 +20,8 @@ class CONTENT_EXPORT UIResourceProvider {
UIResourceClientAndroid* client) = 0; UIResourceClientAndroid* client) = 0;
virtual void DeleteUIResource(cc::UIResourceId resource_id) = 0; virtual void DeleteUIResource(cc::UIResourceId resource_id) = 0;
virtual bool SupportsETC1NonPowerOfTwo() const = 0;
}; };
} // namespace content } // namespace content
......
...@@ -11,6 +11,7 @@ Capabilities::Capabilities() ...@@ -11,6 +11,7 @@ Capabilities::Capabilities()
egl_image_external(false), egl_image_external(false),
texture_format_bgra8888(false), texture_format_bgra8888(false),
texture_format_etc1(false), texture_format_etc1(false),
texture_format_etc1_npot(false),
texture_rectangle(false), texture_rectangle(false),
iosurface(false), iosurface(false),
texture_usage(false), texture_usage(false),
......
...@@ -14,6 +14,7 @@ struct GPU_EXPORT Capabilities { ...@@ -14,6 +14,7 @@ struct GPU_EXPORT Capabilities {
bool egl_image_external; bool egl_image_external;
bool texture_format_bgra8888; bool texture_format_bgra8888;
bool texture_format_etc1; bool texture_format_etc1;
bool texture_format_etc1_npot;
bool texture_rectangle; bool texture_rectangle;
bool iosurface; bool iosurface;
bool texture_usage; bool texture_usage;
......
...@@ -2711,6 +2711,8 @@ Capabilities GLES2DecoderImpl::GetCapabilities() { ...@@ -2711,6 +2711,8 @@ Capabilities GLES2DecoderImpl::GetCapabilities() {
feature_info_->feature_flags().ext_texture_format_bgra8888; feature_info_->feature_flags().ext_texture_format_bgra8888;
caps.texture_format_etc1 = caps.texture_format_etc1 =
feature_info_->feature_flags().oes_compressed_etc1_rgb8_texture; feature_info_->feature_flags().oes_compressed_etc1_rgb8_texture;
caps.texture_format_etc1_npot =
caps.texture_format_etc1 && !workarounds().etc1_power_of_two_only;
caps.texture_rectangle = feature_info_->feature_flags().arb_texture_rectangle; caps.texture_rectangle = feature_info_->feature_flags().arb_texture_rectangle;
caps.texture_usage = feature_info_->feature_flags().angle_texture_usage; caps.texture_usage = feature_info_->feature_flags().angle_texture_usage;
caps.texture_storage = feature_info_->feature_flags().ext_texture_storage; caps.texture_storage = feature_info_->feature_flags().ext_texture_storage;
......
...@@ -19,7 +19,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST( ...@@ -19,7 +19,7 @@ const char kGpuDriverBugListJson[] = LONG_STRING_CONST(
{ {
"name": "gpu driver bug list", "name": "gpu driver bug list",
// Please update the version number whenever you change this file. // Please update the version number whenever you change this file.
"version": "7.2", "version": "7.3",
"entries": [ "entries": [
{ {
"id": 1, "id": 1,
...@@ -1026,6 +1026,19 @@ LONG_STRING_CONST( ...@@ -1026,6 +1026,19 @@ LONG_STRING_CONST(
"features": [ "features": [
"regenerate_struct_names" "regenerate_struct_names"
] ]
},
{
"id": 91,
"cr_bugs": [150500],
"description": "ETC1 non-power-of-two sized textures crash older IMG drivers",
"os": {
"type": "android"
},
"gl_vendor": "Imagination.*",
"gl_renderer": "PowerVR SGX 540.*",
"features": [
"etc1_power_of_two_only"
]
} }
] ]
} }
......
...@@ -42,6 +42,8 @@ ...@@ -42,6 +42,8 @@
disable_oes_standard_derivatives) \ disable_oes_standard_derivatives) \
GPU_OP(DISABLE_POST_SUB_BUFFERS_FOR_ONSCREEN_SURFACES, \ GPU_OP(DISABLE_POST_SUB_BUFFERS_FOR_ONSCREEN_SURFACES, \
disable_post_sub_buffers_for_onscreen_surfaces) \ disable_post_sub_buffers_for_onscreen_surfaces) \
GPU_OP(ETC1_POWER_OF_TWO_ONLY, \
etc1_power_of_two_only) \
GPU_OP(EXIT_ON_CONTEXT_LOST, \ GPU_OP(EXIT_ON_CONTEXT_LOST, \
exit_on_context_lost) \ exit_on_context_lost) \
GPU_OP(FORCE_DISCRETE_GPU, \ GPU_OP(FORCE_DISCRETE_GPU, \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment