gfx::DrawTarget* BasicTextureImage::BeginUpdate(nsIntRegion& aRegion) { NS_ASSERTION(!mUpdateDrawTarget, "BeginUpdate() without EndUpdate()?"); // determine the region the client will need to repaint if (CanUploadSubTextures(mGLContext)) { GetUpdateRegion(aRegion); } else { aRegion = IntRect(IntPoint(0, 0), mSize); } mUpdateRegion = aRegion; IntRect rgnSize = mUpdateRegion.GetBounds(); if (!IntRect(IntPoint(0, 0), mSize).Contains(rgnSize)) { NS_ERROR("update outside of image"); return nullptr; } gfx::SurfaceFormat format = (GetContentType() == gfxContentType::COLOR) ? gfx::SurfaceFormat::B8G8R8X8 : gfx::SurfaceFormat::B8G8R8A8; mUpdateDrawTarget = GetDrawTargetForUpdate(gfx::IntSize(rgnSize.width, rgnSize.height), format); return mUpdateDrawTarget; }
bool TiledTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion& aRegion, const gfx::IntPoint& aFrom /* = gfx::IntPoint(0, 0) */) { if (mSize.width == 0 || mSize.height == 0) { return true; } nsIntRegion region; if (mTextureState != Valid) { IntRect bounds = IntRect(0, 0, mSize.width, mSize.height); region = nsIntRegion(bounds); } else { region = aRegion; } bool result = true; int oldCurrentImage = mCurrentImage; BeginBigImageIteration(); do { IntRect tileRect = GetSrcTileRect(); int xPos = tileRect.x; int yPos = tileRect.y; nsIntRegion tileRegion; tileRegion.And(region, tileRect); // intersect with tile if (tileRegion.IsEmpty()) continue; if (CanUploadSubTextures(mGL)) { tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space } else { // If sub-textures are unsupported, expand to tile boundaries tileRect.x = tileRect.y = 0; tileRegion = nsIntRegion(tileRect); } result &= mImages[mCurrentImage]-> DirectUpdate(aSurf, tileRegion, aFrom + gfx::IntPoint(xPos, yPos)); if (mCurrentImage == mImages.Length() - 1) { // We know we're done, but we still need to ensure that the callback // gets called (e.g. to update the uploaded region). NextTile(); break; } // Override a callback cancelling iteration if the texture wasn't valid. // We need to force the update in that situation, or we may end up // showing invalid/out-of-date texture data. } while (NextTile() || (mTextureState != Valid)); mCurrentImage = oldCurrentImage; mTextureFormat = mImages[0]->GetTextureFormat(); mTextureState = Valid; return result; }
static bool WantsSmallTiles(GLContext* gl) { // We must use small tiles for good performance if we can't use // glTexSubImage2D() for some reason. if (!CanUploadSubTextures(gl)) return true; // We can't use small tiles on the SGX 540, because of races in texture upload. if (gl->WorkAroundDriverBugs() && gl->Renderer() == GLRenderer::SGX540) return false; // Don't use small tiles otherwise. (If we implement incremental texture upload, // then we will want to revisit this.) return false; }
SurfaceFormat UploadImageDataToTexture(GLContext* gl, unsigned char* aData, int32_t aStride, gfxImageFormat aFormat, const nsIntRegion& aDstRegion, GLuint& aTexture, bool aOverwrite, bool aPixelBuffer, GLenum aTextureUnit, GLenum aTextureTarget) { bool textureInited = aOverwrite ? false : true; gl->MakeCurrent(); gl->fActiveTexture(aTextureUnit); if (!aTexture) { gl->fGenTextures(1, &aTexture); gl->fBindTexture(aTextureTarget, aTexture); gl->fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); gl->fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); gl->fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl->fTexParameteri(aTextureTarget, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); textureInited = false; } else { gl->fBindTexture(aTextureTarget, aTexture); } nsIntRegion paintRegion; if (!textureInited) { paintRegion = nsIntRegion(aDstRegion.GetBounds()); } else { paintRegion = aDstRegion; } GLenum format; GLenum internalFormat; GLenum type; int32_t pixelSize = gfxASurface::BytePerPixelFromFormat(aFormat); SurfaceFormat surfaceFormat; MOZ_ASSERT(gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA || gl->GetPreferredARGB32Format() == LOCAL_GL_RGBA); switch (aFormat) { case gfxImageFormatARGB32: if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { format = LOCAL_GL_BGRA; surfaceFormat = gfx::FORMAT_R8G8B8A8; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; } else { format = LOCAL_GL_RGBA; surfaceFormat = gfx::FORMAT_B8G8R8A8; type = LOCAL_GL_UNSIGNED_BYTE; } internalFormat = LOCAL_GL_RGBA; break; case gfxImageFormatRGB24: // Treat RGB24 surfaces as RGBA32 except for the surface // format used. if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { format = LOCAL_GL_BGRA; surfaceFormat = gfx::FORMAT_R8G8B8X8; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; } else { format = LOCAL_GL_RGBA; surfaceFormat = gfx::FORMAT_B8G8R8X8; type = LOCAL_GL_UNSIGNED_BYTE; } internalFormat = LOCAL_GL_RGBA; break; case gfxImageFormatRGB16_565: internalFormat = format = LOCAL_GL_RGB; type = LOCAL_GL_UNSIGNED_SHORT_5_6_5; surfaceFormat = gfx::FORMAT_R5G6B5; break; case gfxImageFormatA8: internalFormat = format = LOCAL_GL_LUMINANCE; type = LOCAL_GL_UNSIGNED_BYTE; // We don't have a specific luminance shader surfaceFormat = gfx::FORMAT_A8; break; default: NS_ASSERTION(false, "Unhandled image surface format!"); format = 0; type = 0; surfaceFormat = gfx::FORMAT_UNKNOWN; } nsIntRegionRectIterator iter(paintRegion); const nsIntRect *iterRect; // Top left point of the region's bounding rectangle. nsIntPoint topLeft = paintRegion.GetBounds().TopLeft(); while ((iterRect = iter.Next())) { // The inital data pointer is at the top left point of the region's // bounding rectangle. We need to find the offset of this rect // within the region and adjust the data pointer accordingly. unsigned char *rectData = aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat); NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0), "Must be uploading to the origin when we don't have an existing texture"); if (textureInited && CanUploadSubTextures(gl)) { TexSubImage2DHelper(gl, aTextureTarget, 0, iterRect->x, iterRect->y, iterRect->width, iterRect->height, aStride, pixelSize, format, type, rectData); } else { TexImage2DHelper(gl, aTextureTarget, 0, internalFormat, iterRect->width, iterRect->height, aStride, pixelSize, 0, format, type, rectData); } } return surfaceFormat; }
SurfaceFormat UploadImageDataToTexture(GLContext* gl, unsigned char* aData, int32_t aStride, SurfaceFormat aFormat, const nsIntRegion& aDstRegion, GLuint aTexture, const gfx::IntSize& aSize, size_t* aOutUploadSize, bool aNeedInit, GLenum aTextureUnit, GLenum aTextureTarget) { gl->MakeCurrent(); gl->fActiveTexture(aTextureUnit); gl->fBindTexture(aTextureTarget, aTexture); GLenum format = 0; GLenum internalFormat = 0; GLenum type = 0; int32_t pixelSize = BytesPerPixel(aFormat); SurfaceFormat surfaceFormat = gfx::SurfaceFormat::UNKNOWN; MOZ_ASSERT(gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA || gl->GetPreferredARGB32Format() == LOCAL_GL_RGBA); switch (aFormat) { case SurfaceFormat::B8G8R8A8: if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { format = LOCAL_GL_BGRA; surfaceFormat = SurfaceFormat::R8G8B8A8; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; } else { format = LOCAL_GL_RGBA; surfaceFormat = SurfaceFormat::B8G8R8A8; type = LOCAL_GL_UNSIGNED_BYTE; } internalFormat = LOCAL_GL_RGBA; break; case SurfaceFormat::B8G8R8X8: // Treat BGRX surfaces as BGRA except for the surface // format used. if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { format = LOCAL_GL_BGRA; surfaceFormat = SurfaceFormat::R8G8B8X8; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; } else { format = LOCAL_GL_RGBA; surfaceFormat = SurfaceFormat::B8G8R8X8; type = LOCAL_GL_UNSIGNED_BYTE; } internalFormat = LOCAL_GL_RGBA; break; case SurfaceFormat::R8G8B8A8: if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { // Upload our RGBA as BGRA, but store that the uploaded format is // BGRA. (sample from R to get B) format = LOCAL_GL_BGRA; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; surfaceFormat = SurfaceFormat::B8G8R8A8; } else { format = LOCAL_GL_RGBA; type = LOCAL_GL_UNSIGNED_BYTE; surfaceFormat = SurfaceFormat::R8G8B8A8; } internalFormat = LOCAL_GL_RGBA; break; case SurfaceFormat::R8G8B8X8: // Treat RGBX surfaces as RGBA except for the surface // format used. if (gl->GetPreferredARGB32Format() == LOCAL_GL_BGRA) { format = LOCAL_GL_BGRA; type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; surfaceFormat = SurfaceFormat::B8G8R8X8; } else { format = LOCAL_GL_RGBA; type = LOCAL_GL_UNSIGNED_BYTE; surfaceFormat = SurfaceFormat::R8G8B8X8; } internalFormat = LOCAL_GL_RGBA; break; case SurfaceFormat::R5G6B5_UINT16: internalFormat = format = LOCAL_GL_RGB; type = LOCAL_GL_UNSIGNED_SHORT_5_6_5; surfaceFormat = SurfaceFormat::R5G6B5_UINT16; break; case SurfaceFormat::A8: internalFormat = format = LOCAL_GL_LUMINANCE; type = LOCAL_GL_UNSIGNED_BYTE; // We don't have a specific luminance shader surfaceFormat = SurfaceFormat::A8; break; default: NS_ASSERTION(false, "Unhandled image surface format!"); } if (aOutUploadSize) { *aOutUploadSize = 0; } if (aNeedInit || !CanUploadSubTextures(gl)) { // If the texture needs initialized, or we are unable to // upload sub textures, then initialize and upload the entire // texture. TexImage2DHelper(gl, aTextureTarget, 0, internalFormat, aSize.width, aSize.height, aStride, pixelSize, 0, format, type, aData); if (aOutUploadSize && aNeedInit) { uint32_t texelSize = GetBytesPerTexel(internalFormat, type); size_t numTexels = size_t(aSize.width) * size_t(aSize.height); *aOutUploadSize += texelSize * numTexels; } } else { // Upload each rect in the region to the texture for (auto iter = aDstRegion.RectIter(); !iter.Done(); iter.Next()) { const IntRect& rect = iter.Get(); const unsigned char* rectData = aData + DataOffset(rect.TopLeft(), aStride, aFormat); TexSubImage2DHelper(gl, aTextureTarget, 0, rect.x, rect.y, rect.Width(), rect.Height(), aStride, pixelSize, format, type, rectData); } } return surfaceFormat; }