// |aTexCoordRect| is the rectangle from the texture that we want to // draw using the given program. The program already has a necessary // offset and scale, so the geometry that needs to be drawn is a unit // square from 0,0 to 1,1. // // |aTexSize| is the actual size of the texture, as it can be larger // than the rectangle given by |aTexCoordRect|. void LayerManagerOGL::BindAndDrawQuadWithTextureRect(LayerProgram *aProg, const nsIntRect& aTexCoordRect, const nsIntSize& aTexSize, GLenum aWrapMode) { GLuint vertAttribIndex = aProg->AttribLocation(LayerProgram::VertexAttrib); GLuint texCoordAttribIndex = aProg->AttribLocation(LayerProgram::TexCoordAttrib); NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?"); // clear any bound VBO so that glVertexAttribPointer() goes back to // "pointer mode" mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); // Given what we know about these textures and coordinates, we can // compute fmod(t, 1.0f) to get the same texture coordinate out. If // the texCoordRect dimension is < 0 or > width/height, then we have // wraparound that we need to deal with by drawing multiple quads, // because we can't rely on full non-power-of-two texture support // (which is required for the REPEAT wrap mode). GLContext::RectTriangles rects; if (aWrapMode == LOCAL_GL_REPEAT) { rects.addRect(/* dest rectangle */ 0.0f, 0.0f, 1.0f, 1.0f, /* tex coords */ aTexCoordRect.x / GLfloat(aTexSize.width), aTexCoordRect.y / GLfloat(aTexSize.height), aTexCoordRect.XMost() / GLfloat(aTexSize.width), aTexCoordRect.YMost() / GLfloat(aTexSize.height)); } else { GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, aTexSize, rects); } mGLContext->fVertexAttribPointer(vertAttribIndex, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer()); mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer()); { mGLContext->fEnableVertexAttribArray(texCoordAttribIndex); { mGLContext->fEnableVertexAttribArray(vertAttribIndex); mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); mGLContext->fDisableVertexAttribArray(vertAttribIndex); } mGLContext->fDisableVertexAttribArray(texCoordAttribIndex); } }
void ImageLayerOGL::RenderLayer(int, const nsIntPoint& aOffset) { nsRefPtr<ImageContainer> container = GetContainer(); if (!container) return; mOGLManager->MakeCurrent(); AutoLockImage autoLock(container); Image *image = autoLock.GetImage(); if (!image) { return; } NS_ASSERTION(image->GetFormat() != Image::REMOTE_IMAGE_BITMAP, "Remote images aren't handled yet in OGL layers!"); NS_ASSERTION(mScaleMode == SCALE_NONE, "Scale modes other than none not handled yet in OGL layers!"); if (image->GetFormat() == Image::PLANAR_YCBCR) { PlanarYCbCrImage *yuvImage = static_cast<PlanarYCbCrImage*>(image); if (!yuvImage->mBufferSize) { return; } PlanarYCbCrOGLBackendData *data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL)); if (data && data->mTextures->GetGLContext() != gl()) { // If these textures were allocated by another layer manager, // clear them out and re-allocate below. data = nsnull; yuvImage->SetBackendData(LayerManager::LAYERS_OPENGL, nsnull); } if (!data) { AllocateTexturesYCbCr(yuvImage); data = static_cast<PlanarYCbCrOGLBackendData*>(yuvImage->GetBackendData(LayerManager::LAYERS_OPENGL)); } if (!data || data->mTextures->GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[2].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[1].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID()); gl()->ApplyFilterToBoundTexture(mFilter); YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram(); program->Activate(); program->SetLayerQuadRect(nsIntRect(0, 0, yuvImage->mSize.width, yuvImage->mSize.height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetYCbCrTextureUnits(0, 1, 2); mOGLManager->BindAndDrawQuadWithTextureRect(program, yuvImage->mData.GetPictureRect(), nsIntSize(yuvImage->mData.mYSize.width, yuvImage->mData.mYSize.height)); // We shouldn't need to do this, but do it anyway just in case // someone else forgets. gl()->fActiveTexture(LOCAL_GL_TEXTURE0); } else if (image->GetFormat() == Image::CAIRO_SURFACE) { CairoImage *cairoImage = static_cast<CairoImage*>(image); if (!cairoImage->mSurface) { return; } CairoOGLBackendData *data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL)); if (data && data->mTexture.GetGLContext() != gl()) { // If this texture was allocated by another layer manager, clear // it out and re-allocate below. data = nsnull; cairoImage->SetBackendData(LayerManager::LAYERS_OPENGL, nsnull); } if (!data) { AllocateTexturesCairo(cairoImage); data = static_cast<CairoOGLBackendData*>(cairoImage->GetBackendData(LayerManager::LAYERS_OPENGL)); } if (!data || data->mTexture.GetGLContext() != gl()) { // XXX - Can this ever happen? If so I need to fix this! return; } gl()->MakeCurrent(); unsigned int iwidth = cairoImage->mSize.width; unsigned int iheight = cairoImage->mSize.height; gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID()); #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO) GLXPixmap pixmap; if (cairoImage->mSurface) { pixmap = sGLXLibrary.CreatePixmap(cairoImage->mSurface); NS_ASSERTION(pixmap, "Failed to create pixmap!"); if (pixmap) { sGLXLibrary.BindTexImage(pixmap); } } #endif ColorTextureLayerProgram *program = mOGLManager->GetColorTextureLayerProgram(data->mLayerProgram); gl()->ApplyFilterToBoundTexture(mFilter); program->Activate(); // The following uniform controls the scaling of the vertex coords. // Instead of setting the scale here and using coords in the range [0,1], we // set an identity transform and use pixel coordinates below program->SetLayerQuadRect(nsIntRect(0, 0, 1, 1)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); nsIntRect rect = GetVisibleRegion().GetBounds(); GLContext::RectTriangles triangleBuffer; float tex_offset_u = float(rect.x % iwidth) / iwidth; float tex_offset_v = float(rect.y % iheight) / iheight; triangleBuffer.addRect(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, tex_offset_u, tex_offset_v, tex_offset_u + float(rect.width) / float(iwidth), tex_offset_v + float(rect.height) / float(iheight)); GLuint vertAttribIndex = program->AttribLocation(LayerProgram::VertexAttrib); GLuint texCoordAttribIndex = program->AttribLocation(LayerProgram::TexCoordAttrib); NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?"); gl()->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); gl()->fVertexAttribPointer(vertAttribIndex, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, triangleBuffer.vertexPointer()); gl()->fVertexAttribPointer(texCoordAttribIndex, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, triangleBuffer.texCoordPointer()); { gl()->fEnableVertexAttribArray(texCoordAttribIndex); { gl()->fEnableVertexAttribArray(vertAttribIndex); gl()->fDrawArrays(LOCAL_GL_TRIANGLES, 0, triangleBuffer.elements()); gl()->fDisableVertexAttribArray(vertAttribIndex); } gl()->fDisableVertexAttribArray(texCoordAttribIndex); } #if defined(MOZ_WIDGET_GTK2) && !defined(MOZ_PLATFORM_MAEMO) if (cairoImage->mSurface && pixmap) { sGLXLibrary.ReleaseTexImage(pixmap); sGLXLibrary.DestroyPixmap(pixmap); } #endif #ifdef XP_MACOSX } else if (image->GetFormat() == Image::MAC_IO_SURFACE) { MacIOSurfaceImage *ioImage = static_cast<MacIOSurfaceImage*>(image); if (!mOGLManager->GetThebesLayerCallback()) { // If its an empty transaction we still need to update // the plugin IO Surface and make sure we grab the // new image ioImage->Update(GetContainer()); image = nsnull; autoLock.Refresh(); image = autoLock.GetImage(); gl()->MakeCurrent(); ioImage = static_cast<MacIOSurfaceImage*>(image); } if (!ioImage) { return; } gl()->fActiveTexture(LOCAL_GL_TEXTURE0); if (!ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)) { AllocateTextureIOSurface(ioImage, gl()); } MacIOSurfaceImageOGLBackendData *data = static_cast<MacIOSurfaceImageOGLBackendData*>(ioImage->GetBackendData(LayerManager::LAYERS_OPENGL)); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, data->mTexture.GetTextureID()); ColorTextureLayerProgram *program = mOGLManager->GetRGBARectLayerProgram(); program->Activate(); if (program->GetTexCoordMultiplierUniformLocation() != -1) { // 2DRect case, get the multiplier right for a sampler2DRect float f[] = { float(ioImage->GetSize().width), float(ioImage->GetSize().height) }; program->SetUniform(program->GetTexCoordMultiplierUniformLocation(), 2, f); } else { NS_ASSERTION(0, "no rects?"); } program->SetLayerQuadRect(nsIntRect(0, 0, ioImage->GetSize().width, ioImage->GetSize().height)); program->SetLayerTransform(GetEffectiveTransform()); program->SetLayerOpacity(GetEffectiveOpacity()); program->SetRenderOffset(aOffset); program->SetTextureUnit(0); mOGLManager->BindAndDrawQuad(program); gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); #endif } GetContainer()->NotifyPaintedImage(image); }
// |aTexCoordRect| is the rectangle from the texture that we want to // draw using the given program. The program already has a necessary // offset and scale, so the geometry that needs to be drawn is a unit // square from 0,0 to 1,1. // // |aTexSize| is the actual size of the texture, as it can be larger // than the rectangle given by |aTexCoordRect|. void CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, const Rect& aTexCoordRect, TextureSource *aTexture) { NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized"); GLuint vertAttribIndex = aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); GLuint texCoordAttribIndex = aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib); NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?"); // Given what we know about these textures and coordinates, we can // compute fmod(t, 1.0f) to get the same texture coordinate out. If // the texCoordRect dimension is < 0 or > width/height, then we have // wraparound that we need to deal with by drawing multiple quads, // because we can't rely on full non-power-of-two texture support // (which is required for the REPEAT wrap mode). GLContext::RectTriangles rects; GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode(); IntSize realTexSize = aTexture->GetSize(); if (!mGLContext->CanUploadNonPowerOfTwo()) { realTexSize = IntSize(NextPowerOfTwo(realTexSize.width), NextPowerOfTwo(realTexSize.height)); } // We need to convert back to actual texels here to get proper behaviour with // our GL helper functions. Should fix this sometime. // I want to vomit. IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width), NS_roundf(aTexCoordRect.y * aTexture->GetSize().height), NS_roundf(aTexCoordRect.width * aTexture->GetSize().width), NS_roundf(aTexCoordRect.height * aTexture->GetSize().height)); // This is fairly disgusting - if the texture should be flipped it will have a // negative height, in which case we un-invert the texture coords and pass the // flipped 'flag' to the functions below. We can't just use the inverted coords // because our GL funtions use an explicit flag. bool flipped = false; if (texCoordRect.height < 0) { flipped = true; texCoordRect.y = texCoordRect.YMost(); texCoordRect.height = -texCoordRect.height; } if (wrapMode == LOCAL_GL_REPEAT) { rects.addRect(/* dest rectangle */ 0.0f, 0.0f, 1.0f, 1.0f, /* tex coords */ texCoordRect.x / GLfloat(realTexSize.width), texCoordRect.y / GLfloat(realTexSize.height), texCoordRect.XMost() / GLfloat(realTexSize.width), texCoordRect.YMost() / GLfloat(realTexSize.height), flipped); } else { nsIntRect tcRect(texCoordRect.x, texCoordRect.y, texCoordRect.width, texCoordRect.height); GLContext::DecomposeIntoNoRepeatTriangles(tcRect, nsIntSize(realTexSize.width, realTexSize.height), rects, flipped); } DrawWithVertexBuffer2(mGLContext, mVBOs, LOCAL_GL_TRIANGLES, rects.elements(), vertAttribIndex, rects.vertexPointer(), texCoordAttribIndex, rects.texCoordPointer()); }