/*static*/void gfxPlatform::InitOffMainThreadCompositing() { static bool inited; if (inited) { return; } inited = true; bool useOffMainThreadCompositing = false; #ifdef MOZ_X11 // On X11 platforms only use OMTC if firefox was initalized with thread-safe // X11 (else it would crash). useOffMainThreadCompositing = (PR_GetEnv("MOZ_USE_OMTC") != NULL); #else useOffMainThreadCompositing = Preferences::GetBool( "layers.offmainthreadcomposition.enabled", false); #endif printf_stderr("Are we using off-main-thread compositing? %s\n", useOffMainThreadCompositing ? "yes" : "NO"); if (useOffMainThreadCompositing) { CompositorParent::CreateCompositorMap(); CompositorParent::CreateThread(); ImageBridgeChild::Create(new base::Thread("ImageBridgeChild")); ImageBridgeChild* imageBridgeChild = ImageBridgeChild::GetSingleton(); ImageBridgeParent* imageBridgeParent = new ImageBridgeParent( CompositorParent::CompositorLoop()); imageBridgeChild->ConnectAsync(imageBridgeParent); } }
void GonkNativeWindow::freeBufferLocked(int i) { ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); if (mSlots[i].mGraphicBuffer != NULL) { // Don't destroy the gralloc buffer if it is still in the // video stream awaiting rendering. if (mSlots[i].mBufferState != BufferSlot::RENDERING) { ibc->DeallocSurfaceDescriptorGralloc(mSlots[i].mSurfaceDescriptor); } mSlots[i].mGraphicBuffer = NULL; mSlots[i].mBufferState = BufferSlot::FREE; mSlots[i].mFrameNumber = 0; } }
void GonkNativeWindow::releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList) { // This function MUST ONLY be called with mMutex unlocked; else there // is a risk of deadlock with the ImageBridge thread. CNW_LOGD("releaseBufferFreeListUnlocked: E"); ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); for (uint32_t i = 0; i < freeList.Length(); ++i) { ibc->DeallocSurfaceDescriptorGralloc(freeList[i]); } freeList.Clear(); CNW_LOGD("releaseBufferFreeListUnlocked: X"); }
void CameraGraphicBuffer::Unlock() { if (mLocked) { android::sp<android::Fence> fence; fence = mReleaseFenceHandle.IsValid() ? mReleaseFenceHandle.mFence : Fence::NO_FENCE; // The window might have been destroyed. The buffer is no longer // valid at that point. sp<GonkNativeWindow> window = mNativeWindow.promote(); if (window.get() && window->returnBuffer(mIndex, mGeneration, fence)) { mLocked = false; } else { // If the window doesn't exist any more, release the buffer // directly. ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor); } } }
status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { if ((w && !h) || (!w && h)) { CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); return BAD_VALUE; } status_t returnFlags(OK); bool updateFormat = false; uint32_t generation; bool alloc = false; int buf = INVALID_BUFFER_SLOT; SurfaceDescriptor descOld; { Mutex::Autolock lock(mMutex); generation = mGeneration; int found = -1; int dequeuedCount = 0; int renderingCount = 0; bool tryAgain = true; CNW_LOGD("dequeueBuffer: E"); while (tryAgain) { if (mAbandoned) { CNW_LOGE("dequeueBuffer: GonkNativeWindow has been abandoned!"); return NO_INIT; } // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; dequeuedCount = 0; renderingCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; } else if (state == BufferSlot::RENDERING) { renderingCount++; } else if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid * stalling the producer if possible. This is because * the consumer may still have pending reads of the * buffers in flight. */ if (found < 0 || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { found = i; } } } // See whether a buffer has been in RENDERING state since the last // setBufferCount so we know whether to perform the // MIN_UNDEQUEUED_BUFFERS check below. if (renderingCount > 0) { // make sure the client is not trying to dequeue more buffers // than allowed. const int avail = mBufferCount - (dequeuedCount + 1); if (avail < MIN_UNDEQUEUED_BUFFERS) { CNW_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded " "(dequeued=%d)", MIN_UNDEQUEUED_BUFFERS, dequeuedCount); return -EBUSY; } } // we're in synchronous mode and didn't find a buffer, we need to // wait for some buffers to be consumed tryAgain = (found == INVALID_BUFFER_SLOT); if (tryAgain) { CNW_LOGD("dequeueBuffer: Try again"); mDequeueCondition.wait(mMutex); CNW_LOGD("dequeueBuffer: Now"); } } if (found == INVALID_BUFFER_SLOT) { // This should not happen. CNW_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } buf = found; *outBuf = found; const bool useDefaultSize = !w && !h; if (useDefaultSize) { // use the default size w = mDefaultWidth; h = mDefaultHeight; } updateFormat = (format != 0); if (!updateFormat) { // keep the current (or default) format format = mPixelFormat; } mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer); alloc = (gbuf == NULL); if ((gbuf!=NULL) && ((uint32_t(gbuf->width) != w) || (uint32_t(gbuf->height) != h) || (uint32_t(gbuf->format) != format) || ((uint32_t(gbuf->usage) & usage) != usage))) { alloc = true; descOld = mSlots[buf].mSurfaceDescriptor; } } // At this point, the buffer is now marked DEQUEUED, and no one else // should touch it, except for freeAllBuffersLocked(); we handle that // after trying to create the surface descriptor below. // // So we don't need mMutex locked, which would otherwise run the risk // of a deadlock on calling AllocSurfaceDescriptorGralloc(). SurfaceDescriptor desc; ImageBridgeChild* ibc; sp<GraphicBuffer> graphicBuffer; if (alloc) { usage |= GraphicBuffer::USAGE_HW_TEXTURE; status_t error; ibc = ImageBridgeChild::GetSingleton(); CNW_LOGD("dequeueBuffer: about to alloc surface descriptor"); ibc->AllocSurfaceDescriptorGralloc(IntSize(w, h), format, usage, &desc); // We can only use a gralloc buffer here. If we didn't get // one back, something went wrong. CNW_LOGD("dequeueBuffer: got surface descriptor"); if (SurfaceDescriptor::TSurfaceDescriptorGralloc != desc.type()) { MOZ_ASSERT(SurfaceDescriptor::T__None == desc.type()); CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); return -ENOMEM; } graphicBuffer = GrallocBufferActor::GetFrom(desc.get_SurfaceDescriptorGralloc()); error = graphicBuffer->initCheck(); if (error != NO_ERROR) { CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d", error); return error; } } bool tooOld = false; { Mutex::Autolock lock(mMutex); if (generation == mGeneration) { if (updateFormat) { mPixelFormat = format; } if (alloc) { mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mSurfaceDescriptor = desc; mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true; mSlots[buf].mRequestBufferCalled = false; returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; } CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, mSlots[buf].mGraphicBuffer->handle); } else { tooOld = true; } } if (alloc && IsSurfaceDescriptorValid(descOld)) { ibc->DeallocSurfaceDescriptorGralloc(descOld); } if (alloc && tooOld) { ibc->DeallocSurfaceDescriptorGralloc(desc); } CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, mSlots[buf].mGraphicBuffer->handle ); CNW_LOGD("dequeueBuffer: X"); return returnFlags; }
void GrallocPlanarYCbCrImage::SetData(const Data& aData) { NS_PRECONDITION(aData.mYSize.width % 2 == 0, "Image should have even width"); NS_PRECONDITION(aData.mYSize.height % 2 == 0, "Image should have even height"); NS_PRECONDITION(aData.mYStride % 16 == 0, "Image should have stride of multiple of 16 pixels"); mData = aData; mSize = aData.mPicSize; if (mSurfaceDescriptor.type() == SurfaceDescriptor::T__None) { ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); ibc->AllocSurfaceDescriptorGralloc(aData.mYSize, HAL_PIXEL_FORMAT_YV12, GraphicBuffer::USAGE_SW_READ_OFTEN | GraphicBuffer::USAGE_SW_WRITE_OFTEN | GraphicBuffer::USAGE_HW_TEXTURE, &mSurfaceDescriptor); } sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(mSurfaceDescriptor.get_SurfaceDescriptorGralloc()); if (!graphicBuffer.get()) { return; } if (graphicBuffer->initCheck() != NO_ERROR) { return; } void* vaddr; if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &vaddr) != OK) { return; } uint8_t* yChannel = static_cast<uint8_t*>(vaddr); gfxIntSize ySize = gfxIntSize(aData.mYSize.width, aData.mYSize.height); int32_t yStride = graphicBuffer->getStride(); uint8_t* vChannel = yChannel + (yStride * ySize.height); gfxIntSize uvSize = gfxIntSize(ySize.width / 2, ySize.height / 2); // Align to 16 bytes boundary int32_t uvStride = ((yStride / 2) + 15) & ~0x0F; uint8_t* uChannel = vChannel + (uvStride * uvSize.height); // Memory outside of the image width may not writable. If the stride // equals to the image width then we can use only one copy. if (yStride == mData.mYStride && yStride == ySize.width) { memcpy(yChannel, mData.mYChannel, yStride * ySize.height); } else { for (int i = 0; i < ySize.height; i++) { memcpy(yChannel + i * yStride, mData.mYChannel + i * mData.mYStride, ySize.width); } } if (uvStride == mData.mCbCrStride && uvStride == uvSize.width) { memcpy(uChannel, mData.mCbChannel, uvStride * uvSize.height); memcpy(vChannel, mData.mCrChannel, uvStride * uvSize.height); } else { for (int i = 0; i < uvSize.height; i++) { memcpy(uChannel + i * uvStride, mData.mCbChannel + i * mData.mCbCrStride, uvSize.width); memcpy(vChannel + i * uvStride, mData.mCrChannel + i * mData.mCbCrStride, uvSize.width); } } graphicBuffer->unlock(); }
GrallocPlanarYCbCrImage::~GrallocPlanarYCbCrImage() { ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); ibc->DeallocSurfaceDescriptorGralloc(mSurfaceDescriptor); }
int GonkNativeWindow::dequeueBuffer(android_native_buffer_t** buffer) { Mutex::Autolock lock(mMutex); int found = -1; int dequeuedCount = 0; bool tryAgain = true; CNW_LOGD("dequeueBuffer: E"); while (tryAgain) { // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; dequeuedCount = 0; for (int i = 0; i < mBufferCount; i++) { const int state = mSlots[i].mBufferState; if (state == BufferSlot::DEQUEUED) { dequeuedCount++; } else if (state == BufferSlot::FREE) { /* We return the oldest of the free buffers to avoid * stalling the producer if possible. This is because * the consumer may still have pending reads of the * buffers in flight. */ bool isOlder = mSlots[i].mFrameNumber < mSlots[found].mFrameNumber; if (found < 0 || isOlder) { found = i; } } } // we're in synchronous mode and didn't find a buffer, we need to // wait for some buffers to be consumed tryAgain = (found == INVALID_BUFFER_SLOT); if (tryAgain) { CNW_LOGD("dequeueBuffer: Try again"); mDequeueCondition.wait(mMutex); CNW_LOGD("dequeueBuffer: Now"); } } if (found == INVALID_BUFFER_SLOT) { // This should not happen. CNW_LOGE("dequeueBuffer: no available buffer slots"); return -EBUSY; } const int buf = found; // buffer is now in DEQUEUED mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer); if (gbuf == NULL) { status_t error; SurfaceDescriptor buffer; ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton(); ibc->AllocSurfaceDescriptorGralloc(gfxIntSize(mDefaultWidth, mDefaultHeight), mPixelFormat, mUsage, &buffer); sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(buffer.get_SurfaceDescriptorGralloc()); if (!graphicBuffer.get()) { return -ENOMEM; } error = graphicBuffer->initCheck(); if (error != NO_ERROR) { CNW_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d",error); return error; } mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mSurfaceDescriptor = buffer; mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true; } *buffer = mSlots[buf].mGraphicBuffer.get(); CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, mSlots[buf].mGraphicBuffer->handle ); CNW_LOGD("dequeueBuffer: X"); return NO_ERROR; }