Tile.cpp revision f85cf343a02e85633e6b68c7f5db3c033b780607
1920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson/* 2920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * Copyright 2010, The Android Open Source Project 3920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * 4920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * Redistribution and use in source and binary forms, with or without 5920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * modification, are permitted provided that the following conditions 6920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * are met: 7920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * * Redistributions of source code must retain the above copyright 8920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * notice, this list of conditions and the following disclaimer. 9920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * * Redistributions in binary form must reproduce the above copyright 10920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * notice, this list of conditions and the following disclaimer in the 11920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * documentation and/or other materials provided with the distribution. 12920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * 13920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 246ba612efffba42bec102ac58a1540496158f747eAndrew Sapperstein */ 25920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 26920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include "config.h" 27d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein#include "BaseTile.h" 28920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 29920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#if USE(ACCELERATED_COMPOSITING) 30920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 31920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include "GLUtils.h" 32920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include "RasterRenderer.h" 33920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include "TextureInfo.h" 34920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include "TilesManager.h" 35920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 36920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include <cutils/atomic.h> 37920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 38920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#ifdef DEBUG 39920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 40920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include <cutils/log.h> 41920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include <wtf/CurrentTime.h> 42920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#include <wtf/text/CString.h> 43920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 44920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#undef XLOG 45920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseTile", __VA_ARGS__) 46d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 47920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#else 48920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 49920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#undef XLOG 50920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#define XLOG(...) 51920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 52920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#endif // DEBUG 53920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 54920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonnamespace WebCore { 55920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 56920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben DodsonBaseTile::BaseTile() 57920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson : m_glWebViewState(0) 58920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_page(0) 59920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_x(-1) 60920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_y(-1) 61920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_texture(0) 62920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_scale(1) 63920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_dirty(true) 64920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_repaintPending(false) 65920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_usable(true) 66920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_lastDirtyPicture(0) 67920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson , m_lastPaintedPicture(0) 68920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 69920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#ifdef DEBUG_COUNT 70920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson ClassTracker::instance()->increment("BaseTile"); 71920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#endif 72920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_currentDirtyAreaIndex = 0; 73920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_renderer = new RasterRenderer(); 74920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 75920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // For EglImage Mode, the internal buffer should be 2. 76920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // And for Async Surface Texture mode, this is 3. 77920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (TilesManager::instance()->getSharedTextureMode() == EglImageMode) 78920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_maxBufferNumber = 2; 79d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein else 80920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_maxBufferNumber = 3; 81920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 82920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirtyArea = new SkRegion[m_maxBufferNumber]; 83920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_fullRepaint = new bool[m_maxBufferNumber]; 84920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson for (int i = 0; i < m_maxBufferNumber; i++) 85920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_fullRepaint[i] = true; 86920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 87920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 88920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben DodsonBaseTile::~BaseTile() 89920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 90920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson setUsedLevel(-1); 91920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture) 92920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture->release(this); 93920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 94920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson delete m_renderer; 95920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson delete[] m_dirtyArea; 96920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson delete[] m_fullRepaint; 97920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 98920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#ifdef DEBUG_COUNT 99920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson ClassTracker::instance()->decrement("BaseTile"); 100920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson#endif 101920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 102920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 103920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson// All the following functions must be called from the main GL thread. 104920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 105920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::setContents(TiledPage* page, int x, int y) 106920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 107920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 108920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_page = page; 109920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_x = x; 110920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_y = y; 111920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 112920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 113920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::reserveTexture() 114920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 115920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson BaseTileTexture* texture = TilesManager::instance()->getAvailableTexture(this); 116920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 117920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 118920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (texture && m_texture != texture) { 119920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_lastPaintedPicture = 0; 120920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson fullInval(); 121920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture = texture; 122920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 123920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 124920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 125920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonbool BaseTile::removeTexture(BaseTileTexture* texture) 126920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 127920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page); 128920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // We update atomically, so paintBitmap() can see the correct value 129920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 130920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture == texture) 131920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture = 0; 132920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return true; 133920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 134920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 135920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::fullInval() 136920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 137920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson for (int i = 0; i < m_maxBufferNumber; i++) { 138920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirtyArea[i].setEmpty(); 139920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_fullRepaint[i] = true; 140920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 141920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 142920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 143920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 144920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::setScale(float scale) 145920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 146920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 147920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_scale != scale) { 148920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_scale = scale; 149920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson fullInval(); 150920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 151920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 152920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 153920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::markAsDirty(int unsigned pictureCount, 154920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson const SkRegion& dirtyArea) 155920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 156920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 157920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_lastDirtyPicture = pictureCount; 158920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson for (int i = 0; i < m_maxBufferNumber; i++) 159920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirtyArea[i].op(dirtyArea, SkRegion::kUnion_Op); 160920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 161920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 162920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 163920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::setUsable(bool usable) 164920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 165920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 166920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_usable = usable; 167920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 168920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 169920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 170920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonbool BaseTile::isDirty() 171920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 172920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 173920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return m_dirty; 174920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 175920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 176920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonbool BaseTile::isRepaintPending() 177920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 178920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 179920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return m_repaintPending; 180920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 181920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 182920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::setRepaintPending(bool pending) 183920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 184920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 185920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_repaintPending = pending; 186920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 187920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 188920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::setUsedLevel(int usedLevel) 189920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 190920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture) 191920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture->setUsedLevel(usedLevel); 192920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 193920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 194920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonint BaseTile::usedLevel() 195920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 196920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture) 197920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return m_texture->usedLevel(); 198920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return -1; 199920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 200920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 201920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::draw(float transparency, SkRect& rect, float scale) 202920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 203920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_x < 0 || m_y < 0 || m_scale != scale) 204920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 205920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 206920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // No need to mutex protect reads of m_texture as it is only written to by 207920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // the consumer thread. 208920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!m_texture) { 209920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("%x on page %x (%d, %d) trying to draw, but no m_texture!", this, m_page, x(), y()); 210920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 211920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 212920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 213920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // Early return if set to un-usable in purpose! 214920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_atomicSync.lock(); 215920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson bool usable = m_usable; 216920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson bool isTexturePainted = m_lastPaintedPicture; 217920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_atomicSync.unlock(); 218920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!usable) { 219920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("early return at BaseTile::draw b/c tile set to unusable !"); 220920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 221920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 222920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!isTexturePainted) { 223920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("early return at BaseTile::draw b/c tile is not painted !"); 224920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 225920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 226920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 227920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson TextureInfo* textureInfo = m_texture->consumerLock(); 228920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!textureInfo) { 229920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("%x (%d, %d) trying to draw, but no textureInfo!", this, x(), y()); 230920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture->consumerRelease(); 231920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 232920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 233920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 234920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture->readyFor(this)) { 235d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein XLOG("draw tile %d, %d, %.2f with texture %x", x(), y(), scale, m_texture); 236920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson TilesManager::instance()->shader()->drawQuad(rect, textureInfo->m_textureId, 237920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson transparency, 238920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson textureInfo->getTextureTarget()); 239920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 240920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture->consumerRelease(); 241920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} 242920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 243920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonbool BaseTile::isTileReady() 244920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 245920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!m_texture) 246920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return false; 247920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_texture->owner() != this) 248920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return false; 249920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 250920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson android::AutoMutex lock(m_atomicSync); 251d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein if (m_dirty) 252920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return false; 253920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 254920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_texture->consumerLock(); 255920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson bool ready = m_texture->readyFor(this); 256d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein m_texture->consumerRelease(); 257d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 258d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein if (ready) 259920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return true; 260920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 261920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 262040992567205c3b6e4ee01bfb2893bceb915357cJoe Onorato return false; 263040992567205c3b6e4ee01bfb2893bceb915357cJoe Onorato} 264040992567205c3b6e4ee01bfb2893bceb915357cJoe Onorato 265920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson// This is called from the texture generation thread 266920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodsonvoid BaseTile::paintBitmap() 267920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson{ 268920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 269920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // We acquire the values below atomically. This ensures that we are reading 270920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // values correctly across cores. Further, once we have these values they 271920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // can be updated by other threads without consequence. 272920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_atomicSync.lock(); 273920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson bool dirty = m_dirty; 274920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson BaseTileTexture* texture = m_texture; 275920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkRegion dirtyArea = m_dirtyArea[m_currentDirtyAreaIndex]; 276920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson float scale = m_scale; 277920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson const int x = m_x; 278920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson const int y = m_y; 279920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_atomicSync.unlock(); 280920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 281920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!dirty || !texture) 282920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 283920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 284920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson TiledPage* tiledPage = m_page; 285920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 286920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson texture->producerAcquireContext(); 287920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson TextureInfo* textureInfo = texture->producerLock(); 288920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 289920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // at this point we can safely check the ownership (if the texture got 290920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // transferred to another BaseTile under us) 291920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (texture->owner() != this || texture->usedLevel() > 1) { 292920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson texture->producerRelease(); 293920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson return; 294920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 295920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 296920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson unsigned int pictureCount = 0; 297920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 298920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // setup the common renderInfo fields; 299920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson TileRenderInfo renderInfo; 300920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.x = x; 301920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.y = y; 302920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.scale = scale; 303920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.tileSize = texture->getSize(); 304920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.tiledPage = tiledPage; 305920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.textureInfo = textureInfo; 306920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 307920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson const float tileWidth = renderInfo.tileSize.width(); 308920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson const float tileHeight = renderInfo.tileSize.height(); 309920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 310920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkRegion::Iterator cliperator(dirtyArea); 311920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 312920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson bool fullRepaint = false; 313920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 314920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // TODO: Implement the partial invalidate in Surface Texture Mode 315920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_fullRepaint[m_currentDirtyAreaIndex] 316920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson || textureInfo->m_width != tileWidth 317920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson || textureInfo->m_height != tileHeight 318920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson || textureInfo->getSharedTextureMode() == SurfaceTextureMode) { 319920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson fullRepaint = true; 320920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 321920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 322920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!fullRepaint) { 323920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson while (!cliperator.done()) { 324920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkRect dirtyRect; 325920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson dirtyRect.set(cliperator.rect()); 326920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 327920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // compute the rect to corresponds to pixels 328920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkRect realTileRect; 329920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realTileRect.fLeft = x * tileWidth; 330920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realTileRect.fTop = y * tileHeight; 331920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realTileRect.fRight = realTileRect.fLeft + tileWidth; 332920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realTileRect.fBottom = realTileRect.fTop + tileHeight; 333920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 334920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // scale the dirtyRect for intersect computation. 335920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkRect realDirtyRect = SkRect::MakeWH(dirtyRect.width() * scale, 336920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson dirtyRect.height() * scale); 337920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realDirtyRect.offset(dirtyRect.fLeft * scale, dirtyRect.fTop * scale); 338920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 339920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // set realTileRect to the intersection of itself and the dirty rect 340920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!realTileRect.intersect(realDirtyRect)) { 341920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson cliperator.next(); 342920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson continue; 343920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 344920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 345920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // initialize finalRealRect to the rounded values of realTileRect 346920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkIRect finalRealRect; 347920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson realTileRect.roundOut(&finalRealRect); 348d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 349d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein // stash the int values of the current width and height 350d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein const int iWidth = finalRealRect.width(); 351d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein const int iHeight = finalRealRect.height(); 352d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 353d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein if (iWidth == tileWidth || iHeight == tileHeight) { 354d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein fullRepaint = true; 355920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson break; 356d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein } 357920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 358920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // translate the rect into tile space coordinates 359920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth); 360d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight); 361920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson finalRealRect.fRight = finalRealRect.fLeft + iWidth; 362d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein finalRealRect.fBottom = finalRealRect.fTop + iHeight; 363920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 364d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein renderInfo.invalRect = &finalRealRect; 365920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.measurePerf = false; 366920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 367920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson pictureCount = m_renderer->renderTiledContent(renderInfo); 368920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 369920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson cliperator.next(); 370920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 371920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 372920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 373920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (fullRepaint) { 374920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson SkIRect rect; 375920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson rect.set(0, 0, tileWidth, tileHeight); 376920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 377920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.invalRect = ▭ 378920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson renderInfo.measurePerf = TilesManager::instance()->getShowVisualIndicator(); 379920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 380920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson pictureCount = m_renderer->renderTiledContent(renderInfo); 381920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 382920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 383920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson XLOG("%x update texture %x for tile %d, %d scale %.2f (m_scale: %.2f)", this, textureInfo, x, y, scale, m_scale); 384920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 385920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_atomicSync.lock(); 386920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson texture->setTile(textureInfo, x, y, scale, pictureCount); 387920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson texture->producerReleaseAndSwap(); 388920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 389920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (texture == m_texture) { 390920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_lastPaintedPicture = pictureCount; 391d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 392920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // set the fullrepaint flags 393920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_fullRepaint[m_currentDirtyAreaIndex] = false; 394920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 395920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // The various checks to see if we are still dirty... 396920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 397920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = false; 398920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 399920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (m_scale != scale) 400920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 401920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 402920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (fullRepaint) 403920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirtyArea[m_currentDirtyAreaIndex].setEmpty(); 404920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson else 405920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirtyArea[m_currentDirtyAreaIndex].op(dirtyArea, SkRegion::kDifference_Op); 406920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 407920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!m_dirtyArea[m_currentDirtyAreaIndex].isEmpty()) 408920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 409920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 410920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // Now we can swap the dirty areas 411920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // TODO: For surface texture in Async mode, the index will be updated 412920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson // according to the current buffer just dequeued. 413920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_currentDirtyAreaIndex = (m_currentDirtyAreaIndex+1) % m_maxBufferNumber; 414d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 415920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!m_dirtyArea[m_currentDirtyAreaIndex].isEmpty()) 416920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_dirty = true; 417920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 418920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson if (!m_dirty) 419920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson m_usable = true; 420920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson } 421920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson 422d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein m_atomicSync.unlock(); 423d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein} 424d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 425920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson} // namespace WebCore 426d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein 427d6eaacbb9eb56763d38a3815fc509b92ed98a585Andrew Sapperstein#endif // USE(ACCELERATED_COMPOSITING) 428920dbbbaca6aa578f3b26d89e99d12754c26ed60Ben Dodson