static void paintWebView(WebKitWebView* webView, Frame* frame, const Region& dirtyRegion) { if (!webView->priv->backingStore) return; Vector<IntRect> rects = dirtyRegion.rects(); coalesceRectsIfPossible(dirtyRegion.bounds(), rects); RefPtr<cairo_t> backingStoreContext = adoptRef(cairo_create(webView->priv->backingStore->cairoSurface())); GraphicsContext gc(backingStoreContext.get()); gc.applyDeviceScaleFactor(frame->page()->deviceScaleFactor()); for (size_t i = 0; i < rects.size(); i++) { const IntRect& rect = rects[i]; gc.save(); gc.clip(rect); if (webView->priv->transparent) gc.clearRect(rect); frame->view()->paint(&gc, rect); gc.restore(); } gc.save(); gc.clip(dirtyRegion.bounds()); frame->page()->inspectorController()->drawHighlight(gc); gc.restore(); }
void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOptions& options) { Region overlapRegion; Region nonOverlapRegion; computeOverlapRegions(overlapRegion, nonOverlapRegion, ResolveSelfOverlapAlways); if (overlapRegion.isEmpty()) { paintSelfAndChildrenWithReplica(options); return; } // Having both overlap and non-overlap regions carries some overhead. Avoid it if the overlap area // is big anyway. if (overlapRegion.bounds().size().area() > nonOverlapRegion.bounds().size().area()) { overlapRegion.unite(nonOverlapRegion); nonOverlapRegion = Region(); } nonOverlapRegion.translate(options.offset); Vector<IntRect> rects = nonOverlapRegion.rects(); for (size_t i = 0; i < rects.size(); ++i) { IntRect rect = rects[i]; if (!rect.intersects(options.textureMapper->clipBounds())) continue; options.textureMapper->beginClip(TransformationMatrix(), rects[i]); paintSelfAndChildrenWithReplica(options); options.textureMapper->endClip(); } rects = overlapRegion.rects(); static const size_t OverlapRegionConsolidationThreshold = 4; if (nonOverlapRegion.isEmpty() && rects.size() > OverlapRegionConsolidationThreshold) { rects.clear(); rects.append(overlapRegion.bounds()); } IntSize maxTextureSize = options.textureMapper->maxTextureSize(); IntRect adjustedClipBounds(options.textureMapper->clipBounds()); adjustedClipBounds.move(-options.offset); for (size_t i = 0; i < rects.size(); ++i) { IntRect rect = rects[i]; for (int x = rect.x(); x < rect.maxX(); x += maxTextureSize.width()) { for (int y = rect.y(); y < rect.maxY(); y += maxTextureSize.height()) { IntRect tileRect(IntPoint(x, y), maxTextureSize); tileRect.intersect(rect); if (!tileRect.intersects(adjustedClipBounds)) continue; paintWithIntermediateSurface(options, tileRect); } } } }
void TextureMapperLayer::computeOverlapRegions(Region& overlapRegion, Region& nonOverlapRegion, ResolveSelfOverlapMode mode) { if (!m_state.visible || !m_state.contentsVisible) return; FloatRect boundingRect; if (m_backingStore || m_state.masksToBounds || m_state.maskLayer || hasFilters()) boundingRect = layerRect(); else if (m_contentsLayer || m_state.solidColor.alpha()) boundingRect = m_state.contentsRect; if (m_currentFilters.hasOutsets()) { FilterOutsets outsets = m_currentFilters.outsets(); IntRect unfilteredTargetRect(boundingRect); boundingRect.move(std::max(0, -outsets.left()), std::max(0, -outsets.top())); boundingRect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom()); boundingRect.unite(unfilteredTargetRect); } TransformationMatrix replicaMatrix; if (m_state.replicaLayer) { replicaMatrix = replicaTransform(); boundingRect.unite(replicaMatrix.mapRect(boundingRect)); } boundingRect = m_currentTransform.combined().mapRect(boundingRect); // Count all masks and filters as overlap layers. if (hasFilters() || m_state.maskLayer || (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)) { Region newOverlapRegion(enclosingIntRect(boundingRect)); nonOverlapRegion.subtract(newOverlapRegion); overlapRegion.unite(newOverlapRegion); return; } Region newOverlapRegion; Region newNonOverlapRegion(enclosingIntRect(boundingRect)); if (!m_state.masksToBounds) { for (auto* child : m_children) child->computeOverlapRegions(newOverlapRegion, newNonOverlapRegion, ResolveSelfOverlapIfNeeded); } if (m_state.replicaLayer) { newOverlapRegion.unite(replicaMatrix.mapRect(newOverlapRegion.bounds())); Region replicaRegion(replicaMatrix.mapRect(newNonOverlapRegion.bounds())); resolveOverlaps(replicaRegion, newOverlapRegion, newNonOverlapRegion); } if ((mode != ResolveSelfOverlapAlways) && shouldBlend()) { newNonOverlapRegion.unite(newOverlapRegion); newOverlapRegion = Region(); } overlapRegion.unite(newOverlapRegion); resolveOverlaps(newNonOverlapRegion, overlapRegion, nonOverlapRegion); }
TEST(Region, Equal) { Region a; a = Rect(2, 3, 4, 5); EXPECT_EQ(Rect(2, 3, 4, 5), a.bounds()); EXPECT_EQ(Rect(2, 3, 4, 5), a[0]); EXPECT_FALSE(a.isEmpty()); a = Rect(6, 7, 8, 9); EXPECT_EQ(Rect(6, 7, 8, 9), a.bounds()); EXPECT_EQ(Rect(6, 7, 8, 9), a[0]); Region b; b = a; EXPECT_EQ(Rect(6, 7, 8, 9), b[0]); b = Rect(0, 0, 0, 0); EXPECT_TRUE(b.isEmpty()); }
void ChromeClientJS::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect) { webkitTrace(); if (m_view->m_private->acceleratedContext && m_view->m_private->acceleratedContext->enabled()) { ASSERT(!rectToScroll.isEmpty()); ASSERT(delta.width() || delta.height()); m_view->m_private->acceleratedContext->scrollNonCompositedContents(rectToScroll, delta); return; } m_rectsToScroll.append(rectToScroll); m_scrollOffsets.append(delta); // The code to calculate the scroll repaint region is originally from WebKit2. // Get the part of the dirty region that is in the scroll rect. Region dirtyRegionInScrollRect = intersect(rectToScroll, m_dirtyRegion); if (!dirtyRegionInScrollRect.isEmpty()) { // There are parts of the dirty region that are inside the scroll rect. // We need to subtract them from the region, move them and re-add them. Region dirtyRegion = Region(m_dirtyRegion); dirtyRegion.subtract(rectToScroll); m_dirtyRegion = dirtyRegion.bounds(); // Move the dirty parts. Region movedDirtyRegionInScrollRect = intersect(translate(dirtyRegionInScrollRect, delta), rectToScroll); // And add them back. m_dirtyRegion.unite(movedDirtyRegionInScrollRect.bounds()); } // Compute the scroll repaint region. We ensure that we are not subtracting areas // that we've scrolled from outside the viewport from the repaint region. IntRect onScreenScrollRect = rectToScroll; onScreenScrollRect.intersect(IntRect(IntPoint(), enclosingIntRect(pageRect()).size())); Region scrollRepaintRegion = subtract(rectToScroll, translate(onScreenScrollRect, delta)); m_dirtyRegion.unite(scrollRepaintRegion.bounds()); m_displayTimer.startOneShot(0); }
Region Transform::transform(const Region& reg) const { Region out; if (UNLIKELY(transformed())) { if (LIKELY(preserveRects())) { Rect r; Region::iterator iterator(reg); while (iterator.iterate(&r)) { out.orSelf(transform(r)); } } else { out.set(transform(reg.bounds())); } } else { out = reg.translate(tx(), ty()); } return out; }
static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const TransformationMatrix& transform) { // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then // apply |transform| to each rect within |region| in order to transform the entire Region. bool clipped; FloatQuad transformedBoundsQuad = CCMathUtil::mapQuad(transform, FloatQuad(region.bounds()), clipped); // FIXME: Find a rect interior to each transformed quad. if (clipped || !transformedBoundsQuad.isRectilinear()) return Region(); Region transformedRegion; Vector<IntRect> rects = region.rects(); // Clipping has been verified above, so mapRect will give correct results. for (size_t i = 0; i < rects.size(); ++i) transformedRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(rects[i])))); return transformedRegion; }
Region Transform::transform(const Region& reg) const { Region out; if (CC_UNLIKELY(type() > TRANSLATE)) { if (CC_LIKELY(preserveRects())) { Region::const_iterator it = reg.begin(); Region::const_iterator const end = reg.end(); while (it != end) { out.orSelf(transform(*it++)); } } else { out.set(transform(reg.bounds())); } } else { int xpos = floorf(tx() + 0.5f); int ypos = floorf(ty() + 0.5f); out = reg.translate(xpos, ypos); } return out; }
static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const TransformationMatrix& transform) { // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then // apply |transform| to each rect within |region| in order to transform the entire Region. IntRect bounds = region.bounds(); FloatRect centeredBounds(-bounds.width() / 2.0, -bounds.height() / 2.0, bounds.width(), bounds.height()); FloatQuad transformedBoundsQuad = transform.mapQuad(FloatQuad(centeredBounds)); if (!transformedBoundsQuad.isRectilinear()) return Region(); Region transformedRegion; IntRect surfaceBounds = surface->contentRect(); Vector<IntRect> rects = region.rects(); Vector<IntRect>::const_iterator end = rects.end(); for (Vector<IntRect>::const_iterator i = rects.begin(); i != end; ++i) { FloatRect centeredOriginRect(-i->width() / 2.0 + i->x() - surfaceBounds.x(), -i->height() / 2.0 + i->y() - surfaceBounds.y(), i->width(), i->height()); FloatRect transformedRect = transform.mapRect(FloatRect(centeredOriginRect)); transformedRegion.unite(enclosedIntRect(transformedRect)); } return transformedRegion; }
void ToolLoopManager::calculateDirtyArea(const Points& points) { // Save the current dirty area if it's needed Region prevDirtyArea; if (m_toolLoop->getTracePolicy() == TracePolicy::Last) prevDirtyArea = m_dirtyArea; // Start with a fresh dirty area m_dirtyArea.clear(); if (points.size() > 0) { Point minpt, maxpt; calculateMinMax(points, minpt, maxpt); // Expand the dirty-area with the pen width Rect r1, r2; m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, minpt.x, minpt.y, r1); m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, maxpt.x, maxpt.y, r2); m_dirtyArea.createUnion(m_dirtyArea, Region(r1.createUnion(r2))); } // Apply offset mode Point offset(m_toolLoop->getOffset()); m_dirtyArea.offset(-offset); // Merge new dirty area with the previous one (for tools like line // or rectangle it's needed to redraw the previous position and // the new one) if (m_toolLoop->getTracePolicy() == TracePolicy::Last) m_dirtyArea.createUnion(m_dirtyArea, prevDirtyArea); // Apply tiled mode TiledMode tiledMode = m_toolLoop->getTiledMode(); if (tiledMode != TiledMode::NONE) { int w = m_toolLoop->sprite()->width(); int h = m_toolLoop->sprite()->height(); Region sprite_area(Rect(0, 0, w, h)); Region outside; outside.createSubtraction(m_dirtyArea, sprite_area); switch (tiledMode) { case TiledMode::X_AXIS: outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h))); break; case TiledMode::Y_AXIS: outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000))); break; } Rect outsideBounds = outside.bounds(); if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0); if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h))); int x1 = outside.bounds().x; while (true) { Region in_sprite; in_sprite.createIntersection(outside, sprite_area); outside.createSubtraction(outside, in_sprite); m_dirtyArea.createUnion(m_dirtyArea, in_sprite); outsideBounds = outside.bounds(); if (outsideBounds.isEmpty()) break; else if (outsideBounds.x+outsideBounds.w > w) outside.offset(-w, 0); else if (outsideBounds.y+outsideBounds.h > h) outside.offset(x1-outsideBounds.x, -h); else break; } } }
status_t TextureManager::loadTexture(Texture* texture, const Region& dirty, const GGLSurface& t) { if (texture->name == -1UL) { status_t err = initTexture(texture); LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err)); return err; } if (texture->target != Texture::TEXTURE_2D) return INVALID_OPERATION; glBindTexture(GL_TEXTURE_2D, texture->name); /* * In OpenGL ES we can't specify a stride with glTexImage2D (however, * GL_UNPACK_ALIGNMENT is a limited form of stride). * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we * need to do something reasonable (here creating a bigger texture). * * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); * * This situation doesn't happen often, but some h/w have a limitation * for their framebuffer (eg: must be multiple of 8 pixels), and * we need to take that into account when using these buffers as * textures. * * This should never be a problem with POT textures */ int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); unpack = 1 << ((unpack > 3) ? 3 : unpack); glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); /* * round to POT if needed */ if (!mGLExtensions.haveNpot()) { texture->NPOTAdjust = true; } if (texture->NPOTAdjust) { // find the smallest power-of-two that will accommodate our surface texture->potWidth = 1 << (31 - clz(t.width)); texture->potHeight = 1 << (31 - clz(t.height)); if (texture->potWidth < t.width) texture->potWidth <<= 1; if (texture->potHeight < t.height) texture->potHeight <<= 1; texture->wScale = float(t.width) / texture->potWidth; texture->hScale = float(t.height) / texture->potHeight; } else { texture->potWidth = t.width; texture->potHeight = t.height; } Rect bounds(dirty.bounds()); GLvoid* data = 0; if (texture->width != t.width || texture->height != t.height) { texture->width = t.width; texture->height = t.height; // texture size changed, we need to create a new one bounds.set(Rect(t.width, t.height)); if (t.width == texture->potWidth && t.height == texture->potHeight) { // we can do it one pass data = t.data; } if (t.format == HAL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture->potWidth, texture->potHeight, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->potWidth, texture->potHeight, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || t.format == HAL_PIXEL_FORMAT_RGBX_8888) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->potWidth, texture->potHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } else if (isSupportedYuvFormat(t.format)) { // just show the Y plane of YUV buffers glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); } else { // oops, we don't handle this format! LOGE("texture=%d, using format %d, which is not " "supported by the GL", texture->name, t.format); } } if (!data) { if (t.format == HAL_PIXEL_FORMAT_RGB_565) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data + bounds.top*t.stride*2); } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data + bounds.top*t.stride*2); } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || t.format == HAL_PIXEL_FORMAT_RGBX_8888) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, t.data + bounds.top*t.stride*4); } else if (isSupportedYuvFormat(t.format)) { // just show the Y plane of YUV buffers glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_LUMINANCE, GL_UNSIGNED_BYTE, t.data + bounds.top*t.stride); } } return NO_ERROR; }
void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, Region& dirty_area) { dirty_area.clear(); if (points.size() > 0) { Point minpt, maxpt; calculateMinMax(points, minpt, maxpt); // Expand the dirty-area with the pen width Rect r1, r2; loop->getPointShape()->getModifiedArea(loop, minpt.x, minpt.y, r1); loop->getPointShape()->getModifiedArea(loop, maxpt.x, maxpt.y, r2); dirty_area.createUnion(dirty_area, Region(r1.createUnion(r2))); } // Apply offset mode Point offset(loop->getOffset()); dirty_area.offset(-offset); // Apply tiled mode TiledMode tiledMode = loop->getDocumentSettings()->getTiledMode(); if (tiledMode != TILED_NONE) { int w = loop->sprite()->width(); int h = loop->sprite()->height(); Region sprite_area(Rect(0, 0, w, h)); Region outside; outside.createSubtraction(dirty_area, sprite_area); switch (tiledMode) { case TILED_X_AXIS: outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h))); break; case TILED_Y_AXIS: outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000))); break; } Rect outsideBounds = outside.bounds(); if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0); if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h))); int x1 = outside.bounds().x; while (true) { Region in_sprite; in_sprite.createIntersection(outside, sprite_area); outside.createSubtraction(outside, in_sprite); dirty_area.createUnion(dirty_area, in_sprite); outsideBounds = outside.bounds(); if (outsideBounds.isEmpty()) break; else if (outsideBounds.x+outsideBounds.w > w) outside.offset(-w, 0); else if (outsideBounds.y+outsideBounds.h > h) outside.offset(x1-outsideBounds.x, -h); else break; } } }
// Strokes are relative to sprite origin. void ToolLoopManager::calculateDirtyArea(const Strokes& strokes) { // Save the current dirty area if it's needed Region prevDirtyArea; if (m_toolLoop->getTracePolicy() == TracePolicy::Last) prevDirtyArea = m_dirtyArea; // Start with a fresh dirty area m_dirtyArea.clear(); const Point celOrigin = m_toolLoop->getCelOrigin(); for (auto& stroke : strokes) { gfx::Rect strokeBounds = stroke.bounds(); if (strokeBounds.isEmpty()) continue; // Expand the dirty-area with the pen width Rect r1, r2; m_toolLoop->getPointShape()->getModifiedArea( m_toolLoop, strokeBounds.x - celOrigin.x, strokeBounds.y - celOrigin.y, r1); m_toolLoop->getPointShape()->getModifiedArea( m_toolLoop, strokeBounds.x+strokeBounds.w-1 - celOrigin.x, strokeBounds.y+strokeBounds.h-1 - celOrigin.y, r2); m_dirtyArea.createUnion(m_dirtyArea, Region(r1.createUnion(r2))); } // Make the dirty area relative to the sprite. m_dirtyArea.offset(celOrigin); // Merge new dirty area with the previous one (for tools like line // or rectangle it's needed to redraw the previous position and // the new one) if (m_toolLoop->getTracePolicy() == TracePolicy::Last) m_dirtyArea.createUnion(m_dirtyArea, prevDirtyArea); // Apply tiled mode TiledMode tiledMode = m_toolLoop->getTiledMode(); if (tiledMode != TiledMode::NONE) { int w = m_toolLoop->sprite()->width(); int h = m_toolLoop->sprite()->height(); Region sprite_area(Rect(0, 0, w, h)); Region outside; outside.createSubtraction(m_dirtyArea, sprite_area); switch (tiledMode) { case TiledMode::X_AXIS: outside.createIntersection(outside, Region(Rect(-w*10000, 0, w*20000, h))); break; case TiledMode::Y_AXIS: outside.createIntersection(outside, Region(Rect(0, -h*10000, w, h*20000))); break; } Rect outsideBounds = outside.bounds(); if (outsideBounds.x < 0) outside.offset(w * (1+((-outsideBounds.x) / w)), 0); if (outsideBounds.y < 0) outside.offset(0, h * (1+((-outsideBounds.y) / h))); int x1 = outside.bounds().x; while (true) { Region in_sprite; in_sprite.createIntersection(outside, sprite_area); outside.createSubtraction(outside, in_sprite); m_dirtyArea.createUnion(m_dirtyArea, in_sprite); outsideBounds = outside.bounds(); if (outsideBounds.isEmpty()) break; else if (outsideBounds.x+outsideBounds.w > w) outside.offset(-w, 0); else if (outsideBounds.y+outsideBounds.h > h) outside.offset(x1-outsideBounds.x, -h); else break; } } }
void LayerBase::loadTexture(const Region& dirty, GLint textureName, const GGLSurface& t, GLuint& textureWidth, GLuint& textureHeight) const { // TODO: defer the actual texture reload until LayerBase::validateTexture // is called. uint32_t flags = mFlags; glBindTexture(GL_TEXTURE_2D, textureName); GLuint tw = t.width; GLuint th = t.height; /* * In OpenGL ES we can't specify a stride with glTexImage2D (however, * GL_UNPACK_ALIGNMENT is 4, which in essence allows a limited form of * stride). * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we * need to do something reasonable (here creating a bigger texture). * * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); * * This situation doesn't happen often, but some h/w have a limitation * for their framebuffer (eg: must be multiple of 8 pixels), and * we need to take that into account when using these buffers as * textures. * * This should never be a problem with POT textures */ tw += (((t.stride - tw) * bytesPerPixel(t.format)) / 4); /* * round to POT if needed */ GLuint texture_w = tw; GLuint texture_h = th; if (!(flags & DisplayHardware::NPOT_EXTENSION)) { // find the smallest power-of-two that will accommodate our surface texture_w = 1 << (31 - clz(t.width)); texture_h = 1 << (31 - clz(t.height)); if (texture_w < t.width) texture_w <<= 1; if (texture_h < t.height) texture_h <<= 1; if (texture_w != tw || texture_h != th) { // we can't use DIRECT_TEXTURE since we changed the size // of the texture flags &= ~DisplayHardware::DIRECT_TEXTURE; } } if (flags & DisplayHardware::DIRECT_TEXTURE) { // here we're guaranteed that texture_{w|h} == t{w|h} if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexImage2D(GL_DIRECT_TEXTURE_2D_QUALCOMM, 0, GL_RGBA, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, t.data); } else if (t.format == GGL_PIXEL_FORMAT_BGRA_8888) { // TODO: add GL_BGRA extension } else { // oops, we don't handle this format, try the regular path goto regular; } textureWidth = tw; textureHeight = th; } else { regular: Rect bounds(dirty.bounds()); GLvoid* data = 0; if (texture_w!=textureWidth || texture_h!=textureHeight) { // texture size changed, we need to create a new one if (!textureWidth || !textureHeight) { // this is the first time, load the whole texture if (texture_w==tw && texture_h==th) { // we can do it one pass data = t.data; } else { // we have to create the texture first because it // doesn't match the size of the buffer bounds.set(Rect(tw, th)); } } if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture_w, texture_h, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_w, texture_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); } else if ( t.format == GGL_PIXEL_FORMAT_YCbCr_422_SP || t.format == GGL_PIXEL_FORMAT_YCbCr_420_SP) { // just show the Y plane of YUV buffers data = t.data; glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texture_w, texture_h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); } else { // oops, we don't handle this format! LOGE("layer %p, texture=%d, using format %d, which is not " "supported by the GL", this, textureName, t.format); textureName = -1; } textureWidth = texture_w; textureHeight = texture_h; } if (!data && textureName>=0) { if (t.format == GGL_PIXEL_FORMAT_RGB_565) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGB, GL_UNSIGNED_SHORT_5_6_5, t.data + bounds.top*t.width*2); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_4444) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, t.data + bounds.top*t.width*2); } else if (t.format == GGL_PIXEL_FORMAT_RGBA_8888) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, bounds.top, t.width, bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, t.data + bounds.top*t.width*4); } } } }