void CCTextureLayerImpl::willDraw(LayerRendererChromium* layerRenderer) { CCLayerImpl::willDraw(layerRenderer); if (m_ioSurfaceChanged) { GraphicsContext3D* context = layerRenderer->context(); Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context->getExtensions()); ASSERT(extensions->supports("GL_CHROMIUM_iosurface")); ASSERT(extensions->supports("GL_ARB_texture_rectangle")); if (!m_ioSurfaceTextureId) m_ioSurfaceTextureId = context->createTexture(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, m_ioSurfaceTextureId)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); extensions->texImageIOSurface2DCHROMIUM(Extensions3D::TEXTURE_RECTANGLE_ARB, m_ioSurfaceSize.width(), m_ioSurfaceSize.height(), m_ioSurfaceId, 0); // Do not check for error conditions. texImageIOSurface2DCHROMIUM is supposed to hold on to // the last good IOSurface if the new one is already closed. This is only a possibility // during live resizing of plugins. However, it seems that this is not sufficient to // completely guard against garbage being drawn. If this is found to be a significant issue, // it may be necessary to explicitly tell the embedder when to free the surfaces it has // allocated. m_ioSurfaceChanged = false; } }
void LayerTextureSubImage::uploadWithMapTexSubImage(const uint8_t* image, const IntRect& imageRect, const IntRect& sourceRect, const IntRect& destRect, GC3Denum format, GraphicsContext3D* context) { TRACE_EVENT("LayerTextureSubImage::uploadWithMapTexSubImage", this, 0); // Offset from image-rect to source-rect. IntPoint offset(sourceRect.x() - imageRect.x(), sourceRect.y() - imageRect.y()); // Upload tile data via a mapped transfer buffer Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context->getExtensions()); uint8_t* pixelDest = static_cast<uint8_t*>(extensions->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, destRect.x(), destRect.y(), destRect.width(), destRect.height(), format, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY)); if (!pixelDest) { uploadWithTexSubImage(image, imageRect, sourceRect, destRect, format, context); return; } if (imageRect.width() == sourceRect.width() && !offset.x()) memcpy(pixelDest, &image[4 * offset.y() * imageRect.width()], imageRect.width() * destRect.height() * 4); else { // Strides not equal, so do a row-by-row memcpy from the // paint results into the pixelDest for (int row = 0; row < destRect.height(); ++row) memcpy(&pixelDest[destRect.width() * 4 * row], &image[4 * (offset.x() + (offset.y() + row) * imageRect.width())], destRect.width() * 4); } extensions->unmapTexSubImage2DCHROMIUM(pixelDest); }
void RateLimiter::rateLimitContext(Timer<RateLimiter>*) { TRACE_EVENT("RateLimiter::rateLimitContext", this, 0); Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(m_context->getExtensions()); extensions->rateLimitOffscreenContextCHROMIUM(); }
void WebGLLayerChromium::rateLimitContext(Timer<WebGLLayerChromium>*) { TRACE_EVENT("WebGLLayerChromium::rateLimitContext", this, 0); if (!m_context) return; Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(m_context->getExtensions()); extensions->rateLimitOffscreenContextCHROMIUM(); }
bool WebGLLayerChromium::paintRenderedResultsToCanvas(ImageBuffer* imageBuffer) { if (m_textureUpdated || !layerRendererContext() || !drawsContent()) return false; IntSize framebufferSize = context()->getInternalFramebufferSize(); ASSERT(layerRendererContext()); // This would ideally be done in the webgl context, but that isn't possible yet. Platform3DObject framebuffer = layerRendererContext()->createFramebuffer(); layerRendererContext()->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); layerRendererContext()->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_textureId, 0); Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(layerRendererContext()->getExtensions()); extensions->paintFramebufferToCanvas(framebuffer, framebufferSize.width(), framebufferSize.height(), !context()->getContextAttributes().premultipliedAlpha, imageBuffer); layerRendererContext()->deleteFramebuffer(framebuffer); return true; }
bool WebGLLayerChromium::paintRenderedResultsToCanvas(ImageBuffer* imageBuffer) { if (!m_drawingBuffer || !drawsContent()) return false; IntSize framebufferSize = context()->getInternalFramebufferSize(); // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding). // FIXME: The WebGLRenderingContext tracks the current framebuffer binding, it would be slightly more efficient to use this value // rather than querying it off of the context. GC3Dint previousFramebuffer = 0; context()->getIntegerv(GraphicsContext3D::FRAMEBUFFER_BINDING, &previousFramebuffer); Platform3DObject framebuffer = context()->createFramebuffer(); context()->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, framebuffer); context()->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_textureId, 0); Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context()->getExtensions()); extensions->paintFramebufferToCanvas(framebuffer, framebufferSize.width(), framebufferSize.height(), !context()->getContextAttributes().premultipliedAlpha, imageBuffer); context()->deleteFramebuffer(framebuffer); context()->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, previousFramebuffer); return true; }
void CCHeadsUpDisplay::draw() { GraphicsContext3D* context = m_layerRenderer->context(); if (!m_hudTexture) m_hudTexture = ManagedTexture::create(m_layerRenderer->renderSurfaceTextureManager()); // Use a fullscreen texture only if we need to... IntSize hudSize; if (settings().showPlatformLayerTree) { hudSize.setWidth(min(2048, m_layerRenderer->viewportWidth())); hudSize.setHeight(min(2048, m_layerRenderer->viewportHeight())); } else { hudSize.setWidth(512); hudSize.setHeight(128); } if (!m_hudTexture->reserve(hudSize, GraphicsContext3D::RGBA)) return; // Render pixels into the texture. PlatformCanvas canvas; canvas.resize(hudSize); { PlatformCanvas::Painter painter(&canvas, PlatformCanvas::Painter::GrayscaleText); drawHudContents(painter.context(), hudSize); } // Upload to GL. { PlatformCanvas::AutoLocker locker(&canvas); m_hudTexture->bindTexture(context, m_layerRenderer->renderSurfaceTextureAllocator()); bool uploadedViaMap = false; if (m_useMapSubForUploads) { Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context->getExtensions()); uint8_t* pixelDest = static_cast<uint8_t*>(extensions->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, hudSize.width(), hudSize.height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY)); if (pixelDest) { uploadedViaMap = true; memcpy(pixelDest, locker.pixels(), hudSize.width() * hudSize.height() * 4); extensions->unmapTexSubImage2DCHROMIUM(pixelDest); } } if (!uploadedViaMap) { GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, canvas.size().width(), canvas.size().height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, locker.pixels())); } } // Draw the HUD onto the default render surface. const Program* program = m_layerRenderer->headsUpDisplayProgram(); ASSERT(program && program->initialized()); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); m_hudTexture->bindTexture(context, m_layerRenderer->renderSurfaceTextureAllocator()); GLC(context, context->useProgram(program->program())); GLC(context, context->uniform1i(program->fragmentShader().samplerLocation(), 0)); TransformationMatrix matrix; matrix.translate3d(hudSize.width() * 0.5, hudSize.height() * 0.5, 0); m_layerRenderer->drawTexturedQuad(matrix, hudSize.width(), hudSize.height(), 1.0f, m_layerRenderer->sharedGeometryQuad(), program->vertexShader().matrixLocation(), program->fragmentShader().alphaLocation(), -1); m_hudTexture->unreserve(); }
void LayerRendererChromium::updateLayers(LayerList& renderSurfaceLayerList) { TRACE_EVENT("LayerRendererChromium::updateLayers", this, 0); CCLayerImpl* rootDrawLayer = m_rootLayer->ccLayerImpl(); if (!rootDrawLayer->renderSurface()) rootDrawLayer->createRenderSurface(); ASSERT(rootDrawLayer->renderSurface()); rootDrawLayer->renderSurface()->m_contentRect = IntRect(IntPoint(0, 0), m_viewportVisibleRect.size()); IntRect rootScissorRect(m_viewportVisibleRect); // The scissorRect should not include the scroll offset. rootScissorRect.move(-m_viewportScrollPosition.x(), -m_viewportScrollPosition.y()); rootDrawLayer->setScissorRect(rootScissorRect); m_defaultRenderSurface = rootDrawLayer->renderSurface(); renderSurfaceLayerList.append(rootDrawLayer); TransformationMatrix identityMatrix; m_defaultRenderSurface->m_layerList.clear(); // Unfortunately, updatePropertiesAndRenderSurfaces() currently both updates the layers and updates the draw state // (transforms, etc). It'd be nicer if operations on the presentation layers happened later, but the draw // transforms are needed by large layers to determine visibility. Tiling will fix this by eliminating the // concept of a large content layer. updatePropertiesAndRenderSurfaces(rootDrawLayer, identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList); #ifndef NDEBUG s_inPaintLayerContents = true; #endif paintLayerContents(renderSurfaceLayerList); #ifndef NDEBUG s_inPaintLayerContents = false; #endif // FIXME: Before updateCompositorResourcesRecursive, when the compositor runs in // its own thread, and when the copyTexImage2D bug is fixed, insert // a glWaitLatch(Compositor->Offscreen) on all child contexts here instead // of after updateCompositorResourcesRecursive. // Also uncomment the glSetLatch(Compositor->Offscreen) code in addChildContext. // if (hardwareCompositing() && m_contextSupportsLatch) { // // For each child context: // // glWaitLatch(Compositor->Offscreen); // ChildContextMap::iterator i = m_childContexts.begin(); // for (; i != m_childContexts.end(); ++i) { // Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); // GC3Duint childToParentLatchId, parentToChildLatchId; // ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); // ext->waitLatchCHROMIUM(parentToChildLatchId); // } // } updateCompositorResourcesRecursive(m_rootLayer.get()); // After updateCompositorResourcesRecursive, set/wait latches for all child // contexts. This will prevent the compositor from using any of the child // parent textures while WebGL commands are executing from javascript *and* // while the final parent texture is being blit'd. copyTexImage2D // uses the parent texture as a temporary resolve buffer, so that's why the // waitLatch is below, to block the compositor from using the parent texture // until the next WebGL SwapBuffers (or copyTextureToParentTexture for // Canvas2D). if (hardwareCompositing() && m_contextSupportsLatch) { m_childContextsWereCopied = true; // For each child context: // glSetLatch(Offscreen->Compositor); // glWaitLatch(Compositor->Offscreen); ChildContextMap::iterator i = m_childContexts.begin(); for (; i != m_childContexts.end(); ++i) { Extensions3DChromium* ext = static_cast<Extensions3DChromium*>(i->first->getExtensions()); GC3Duint childToParentLatchId, parentToChildLatchId; ext->getParentToChildLatchCHROMIUM(&parentToChildLatchId); ext->getChildToParentLatchCHROMIUM(&childToParentLatchId); ext->setLatchCHROMIUM(childToParentLatchId); ext->waitLatchCHROMIUM(parentToChildLatchId); } } }
void LayerRendererChromium::updateAndDrawLayers() { // FIXME: use the frame begin time from the overall compositor scheduler. // This value is currently inaccessible because it is up in Chromium's // RenderWidget. m_headsUpDisplay->onFrameBegin(currentTime()); ASSERT(m_hardwareCompositing); if (!m_rootLayer) return; updateRootLayerContents(); // Recheck that we still have a root layer. This may become null if // compositing gets turned off during a paint operation. if (!m_rootLayer) return; { TRACE_EVENT("LayerRendererChromium::synchronizeTrees", this, 0); m_rootCCLayerImpl = TreeSynchronizer::synchronizeTrees(m_rootLayer.get(), m_rootCCLayerImpl.get()); } LayerList renderSurfaceLayerList; updateLayers(renderSurfaceLayerList); // Before drawLayers: if (hardwareCompositing() && m_contextSupportsLatch) { // FIXME: The multithreaded compositor case will not work as long as // copyTexImage2D resolves to the parent texture, because the main // thread can execute WebGL calls on the child context at any time, // potentially clobbering the parent texture that is being renderered // by the compositor thread. if (m_childContextsWereCopied) { Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); // For each child context: // glWaitLatch(Offscreen->Compositor); ChildContextMap::iterator i = m_childContexts.begin(); for (; i != m_childContexts.end(); ++i) { Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); GC3Duint latchId; childExt->getChildToParentLatchCHROMIUM(&latchId); parentExt->waitLatchCHROMIUM(latchId); } } // Reset to false to indicate that we have consumed the dirty child // contexts' parent textures. (This is only useful when the compositor // is multithreaded.) m_childContextsWereCopied = false; } drawLayers(renderSurfaceLayerList); m_textureManager->unprotectAllTextures(); // After drawLayers: if (hardwareCompositing() && m_contextSupportsLatch) { Extensions3DChromium* parentExt = static_cast<Extensions3DChromium*>(m_context->getExtensions()); // For each child context: // glSetLatch(Compositor->Offscreen); ChildContextMap::iterator i = m_childContexts.begin(); for (; i != m_childContexts.end(); ++i) { Extensions3DChromium* childExt = static_cast<Extensions3DChromium*>(i->first->getExtensions()); GC3Duint latchId; childExt->getParentToChildLatchCHROMIUM(&latchId); parentExt->setLatchCHROMIUM(latchId); } } if (isCompositingOffscreen()) copyOffscreenTextureToDisplay(); }
void CCPluginLayerImpl::draw(LayerRendererChromium* layerRenderer) { ASSERT(CCProxy::isImplThread()); if (m_ioSurfaceChanged) { GraphicsContext3D* context = layerRenderer->context(); Extensions3DChromium* extensions = static_cast<Extensions3DChromium*>(context->getExtensions()); ASSERT(extensions->supports("GL_CHROMIUM_iosurface")); ASSERT(extensions->supports("GL_ARB_texture_rectangle")); if (!m_ioSurfaceTextureId) m_ioSurfaceTextureId = context->createTexture(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, m_ioSurfaceTextureId)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(context, context->texParameteri(Extensions3D::TEXTURE_RECTANGLE_ARB, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); extensions->texImageIOSurface2DCHROMIUM(Extensions3D::TEXTURE_RECTANGLE_ARB, m_ioSurfaceWidth, m_ioSurfaceHeight, m_ioSurfaceId, 0); // Do not check for error conditions. texImageIOSurface2DCHROMIUM is supposed to hold on to // the last good IOSurface if the new one is already closed. This is only a possibility // during live resizing of plugins. However, it seems that this is not sufficient to // completely guard against garbage being drawn. If this is found to be a significant issue, // it may be necessary to explicitly tell the embedder when to free the surfaces it has // allocated. m_ioSurfaceChanged = false; } if (m_ioSurfaceTextureId) { TexTransformPluginProgramBinding binding; if (m_flipped) binding.set(layerRenderer->pluginLayerTexRectProgramFlip()); else binding.set(layerRenderer->pluginLayerTexRectProgram()); GraphicsContext3D* context = layerRenderer->context(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, m_ioSurfaceTextureId)); GLC(context, context->useProgram(binding.programId)); GLC(context, context->uniform1i(binding.samplerLocation, 0)); // Note: this code path ignores m_uvRect. GLC(context, context->uniform4f(binding.texTransformLocation, 0, 0, m_ioSurfaceWidth, m_ioSurfaceHeight)); layerRenderer->drawTexturedQuad(drawTransform(), bounds().width(), bounds().height(), drawOpacity(), layerRenderer->sharedGeometryQuad(), binding.matrixLocation, binding.alphaLocation, -1); GLC(context, context->bindTexture(Extensions3D::TEXTURE_RECTANGLE_ARB, 0)); } else { TexStretchPluginProgramBinding binding; if (m_flipped) binding.set(layerRenderer->pluginLayerProgramFlip()); else binding.set(layerRenderer->pluginLayerProgram()); GraphicsContext3D* context = layerRenderer->context(); GLC(context, context->activeTexture(GraphicsContext3D::TEXTURE0)); GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_textureId)); // FIXME: setting the texture parameters every time is redundant. Move this code somewhere // where it will only happen once per texture. GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(context, context->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE)); GLC(context, context->useProgram(binding.programId)); GLC(context, context->uniform1i(binding.samplerLocation, 0)); GLC(context, context->uniform2f(binding.offsetLocation, m_uvRect.x(), m_uvRect.y())); GLC(context, context->uniform2f(binding.scaleLocation, m_uvRect.width(), m_uvRect.height())); layerRenderer->drawTexturedQuad(drawTransform(), bounds().width(), bounds().height(), drawOpacity(), layerRenderer->sharedGeometryQuad(), binding.matrixLocation, binding.alphaLocation, -1); } }