/* * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "CanvasTexture" #define LOG_NDEBUG 1 #include "config.h" #include "CanvasTexture.h" #if USE(ACCELERATED_COMPOSITING) #include "AndroidLog.h" #include "GLUtils.h" #include "Image.h" #include "ImageBuffer.h" #include "SkBitmap.h" #include "SkBitmapRef.h" #include "SkDevice.h" #include "SkPixelRef.h" #include #include #include namespace WebCore { static int s_maxTextureSize = 0; static HashMap s_textures; static android::Mutex s_texturesLock; /******************************************** * Called by both threads ********************************************/ PassRefPtr CanvasTexture::getCanvasTexture(CanvasLayer* layer) { android::Mutex::Autolock lock(s_texturesLock); RefPtr texture = s_textures.get(layer->uniqueId()); if (texture.get()) return texture.release(); return adoptRef(new CanvasTexture(layer->uniqueId())); } bool CanvasTexture::setHwAccelerated(bool hwAccelerated) { android::Mutex::Autolock lock(m_surfaceLock); if (m_useHwAcceleration == hwAccelerated) return false; m_useHwAcceleration = hwAccelerated; if (!m_ANW.get()) return false; destroySurfaceTextureLocked(); return true; } /******************************************** * Called by WebKit thread ********************************************/ void CanvasTexture::setSize(const IntSize& size) { android::Mutex::Autolock lock(m_surfaceLock); if (m_size == size) return; m_size = size; if (m_ANW.get()) { if (useSurfaceTexture()) { int result = native_window_set_buffers_dimensions(m_ANW.get(), m_size.width(), m_size.height()); GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result); if (result != NO_ERROR) m_useHwAcceleration = false; // On error, drop out of HWA } if (!useSurfaceTexture()) destroySurfaceTextureLocked(); } } SurfaceTextureClient* CanvasTexture::nativeWindow() { android::Mutex::Autolock lock(m_surfaceLock); if (m_ANW.get()) return m_ANW.get(); if (!m_texture) return 0; if (!useSurfaceTexture()) return 0; m_surfaceTexture = new android::SurfaceTexture(m_texture, false); m_ANW = new android::SurfaceTextureClient(m_surfaceTexture); int result = native_window_set_buffers_format(m_ANW.get(), HAL_PIXEL_FORMAT_RGBA_8888); GLUtils::checkSurfaceTextureError("native_window_set_buffers_format", result); if (result == NO_ERROR) { result = native_window_set_buffers_dimensions(m_ANW.get(), m_size.width(), m_size.height()); GLUtils::checkSurfaceTextureError("native_window_set_buffers_dimensions", result); } if (result != NO_ERROR) { m_useHwAcceleration = false; destroySurfaceTextureLocked(); return 0; } return m_ANW.get(); } bool CanvasTexture::uploadImageBuffer(ImageBuffer* imageBuffer) { m_hasValidTexture = false; SurfaceTextureClient* anw = nativeWindow(); if (!anw) return false; // Size mismatch, early abort (will fall back to software) if (imageBuffer->size() != m_size) return false; SkCanvas* canvas = imageBufferCanvas(imageBuffer); if (!canvas) return false; const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); if (!GLUtils::updateSharedSurfaceTextureWithBitmap(anw, bitmap)) return false; m_hasValidTexture = true; return true; } /******************************************** * Called by UI thread WITH GL context ********************************************/ CanvasTexture::~CanvasTexture() { if (m_layerId) { s_texturesLock.lock(); s_textures.remove(m_layerId); s_texturesLock.unlock(); } if (m_texture) GLUtils::deleteTexture(&m_texture); } void CanvasTexture::requireTexture() { android::Mutex::Autolock lock(m_surfaceLock); if (!m_texture) glGenTextures(1, &m_texture); if (!s_maxTextureSize) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &s_maxTextureSize); } bool CanvasTexture::updateTexImage() { android::Mutex::Autolock lock(m_surfaceLock); if (!m_surfaceTexture.get()) return false; status_t result = m_surfaceTexture->updateTexImage(); if (result != OK) { ALOGE("unexpected error: updateTexImage return %d", result); return false; } return true; } /******************************************** * Called by both threads ********************************************/ void CanvasTexture::destroySurfaceTextureLocked() { if (m_ANW.get()) { m_ANW.clear(); m_surfaceTexture->abandon(); m_surfaceTexture.clear(); } } /******************************************** * Called by WebKit thread ********************************************/ CanvasTexture::CanvasTexture(int layerId) : m_size() , m_layerId(layerId) , m_texture(0) , m_surfaceTexture(0) , m_ANW(0) , m_hasValidTexture(false) , m_useHwAcceleration(true) { s_textures.add(m_layerId, this); } // TODO: Have a global limit as well as a way to react to low memory situations bool CanvasTexture::useSurfaceTexture() { if (!m_useHwAcceleration) return false; if (m_size.isEmpty()) return false; return (m_size.width() < s_maxTextureSize) && (m_size.height() < s_maxTextureSize); } } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING)