Open Bug 711819 Opened 14 years ago Updated 3 years ago

use neon fastpath in ConvertYCbCrToRGB32

Categories

(Core :: Graphics, defect)

All
Android
defect

Tracking

()

blocking-basecamp -

People

(Reporter: gal, Unassigned)

Details

Attachments

(2 files, 3 obsolete files)

Android has hardware support for YUV2RGB conversion with mirroring and rotation through the "copybit" device contained in libhardware.so. See hardware/libhardware/include/hardware/copybit.h for the API. We should use this for ConvertYCbCrToRGB32 and ScaleYCbCrToRGB32 since its hardware accelerated on some phones. This is going to help B2G as well, obviously.
We need to figure out how this is implemented before deciding whether it would help us. We (already?) have code to unpack yuv with shaders during compositing, which is optimal wrt memory bandwidth.
Maybe we could use copybit when GL acceleration is not available. The question is whether there are many devices where that would be a win.
Hi all, I found a chrome patch which optimizes YUV2RGB performance by NEON assembly, http://code.google.com/p/chromium/issues/detail?id=71403 In Cubevid apps, the major hotspot "FastConvertYUVToRGB32Row_C" reduced quite a lot from 23% to 3%. BR James
Attached file yuv2rgb neon patch (obsolete) —
yuv2rgb neon patch
Attachment #684354 - Attachment is patch: false
Attachment #684354 - Attachment mime type: text/plain → application/x-tgz
Attached patch Patch (obsolete) — Splinter Review
Here's a version that applies well.
Comment on attachment 684409 [details] [diff] [review] Patch Randrom r? request to get this process kicked off.
Attachment #684409 - Flags: review?(jones.chris.g)
Hi all, You can test this path and use it in FFOS. It improves Cubevid performance. BR James
Attachment #684409 - Flags: review?(jones.chris.g) → review+
I expect that this patch will need to be properly added to the infrastructure like update.sh and the README in gfx/ycbcr as well.
update.sh doesn't work for me any more, I think that machinery is out of date. I am ok with just patching over it.
I would like to capture a stack to see why we end up here though. I would have thought we do this with GL.
wow, ok, no wonder this is slow: (gdb) bt 30 #0 mozilla::gfx::ConvertYCbCrToRGB32 ( y_buf=0x4316401c "\033\033\033\033\033\033\033\033", '\034' <repeats 14 times>, "\035\035\035\035", '\036' <repeats 28 times>, "\037\037\037\037 \037\037\037\037", '\036' <repeats 33 times>, "\034\033\032\032\032\032\032\032\032\032\032\033\033\034\034\035\033\032\031\031\031\031\031\031\031\031\031\032\032\032\032\032\030\027\025\025\025\026\026\030\030\031\031\031\030\027\026\025\022\021\020\020\016\r\017\024\027\031\033\036!$&''''()+,---,+**))()*++++,-/01100000023"..., u_buf=0x4319c41c '\177' <repeats 103 times>, "~\200\205\214\225\230\230\230\221\204\203\201", '\177' <repeats 11 times>, "~zuss", 't' <repeats 45 times>, "uuvwxxxxxxxyyzz{{||{{z"..., v_buf=0x431aa51c "\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\203\201\200", '\177' <repeats 15 times>"\200, \200\201\201\202\203\204\205\205\206\206\206\206\206\206\206\206\206\206\206\206\206\206\206\205\205\204\204\203\203\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202\202"..., rgb_buf=0x4c501000 "", pic_x=0, pic_y=0, pic_width=640, pic_height=360, y_pitch=640, uv_pitch=320, rgb_pitch=2560, yuv_type=mozilla::gfx::YV12) at /Users/gal/workspace/B2G/gecko/gfx/ycbcr/yuv_convert.cpp:62 #1 0x40f17ee4 in gfxUtils::ConvertYCbCrToRGB (aData=..., aDestFormat=@0xbe93f91c, aDestSize=<value optimized out>, aDestBuffer=0x4c501000 "", aStride=2560) at /Users/gal/workspace/B2G/gecko/gfx/thebes/gfxUtils.cpp:772 #2 0x40f27ec4 in mozilla::layers::PlanarYCbCrImage::GetAsSurface (this=0x469d2690) at /Users/gal/workspace/B2G/gecko/gfx/layers/ImageContainer.cpp:502 #3 0x40f40a64 in mozilla::layers::SharedPlanarYCbCrImage::GetAsSurface (this=0x4316401c) at /Users/gal/workspace/B2G/gecko/gfx/layers/ipc/ImageContainerChild.cpp:495 #4 0x40f284da in mozilla::layers::ImageContainer::GetCurrentAsSurface (this=0x46f23940, aSize=0xbe93f970) at /Users/gal/workspace/B2G/gecko/gfx/layers/ImageContainer.cpp:323 #5 0x40813fb8 in nsLayoutUtils::SurfaceFromElement (aElement=0x40379480, aSurfaceFlags=<value optimized out>) at /Users/gal/workspace/B2G/gecko/layout/base/nsLayoutUtils.cpp:4490 #6 0x40e8026e in mozilla::WebGLContext::SurfaceFromElement<nsHTMLVideoElement> (cx=0x46e49b00, obj=<value optimized out>, self=0x439a5980, argc=<value optimized out>, vp=0x42a38128) at /Users/gal/workspace/B2G/gecko/content/canvas/src/WebGLContext.h:1289 #7 mozilla::WebGLContext::TexImage2D<nsHTMLVideoElement> (cx=0x46e49b00, obj=<value optimized out>, self=0x439a5980, argc=<value optimized out>, vp=0x42a38128) at /Users/gal/workspace/B2G/gecko/content/canvas/src/WebGLContext.h:863 #8 texImage2D (cx=0x46e49b00, obj=<value optimized out>, self=0x439a5980, argc=<value optimized out>, vp=0x42a38128) at /Users/gal/workspace/B2G/objdir-gecko/dom/bindings/WebGLRenderingContextBinding.cpp:7238 #9 0x40e83872 in genericMethod (cx=0x46e49b00, argc=6, vp=0x42a38128) at /Users/gal/workspace/B2G/objdir-gecko/dom/bindings/WebGLRenderingContextBinding.cpp:9625 #10 0x41151466 in CallJSNative (cx=0x46e49b00, args=..., construct=js::NO_CONSTRUCT) at /Users/gal/workspace/B2G/gecko/js/src/jscntxtinlines.h:364 #11 InvokeKernel (cx=0x46e49b00, args=..., construct=js::NO_CONSTRUCT) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.cpp:369 #12 0x4114e518 in js::Interpret (cx=0x46e49b00, entryFrame=<value optimized out>, interpMode=<value optimized out>) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.cpp:2331 #13 0x41150d26 in js::RunScript (cx=0x46e49b00, script=<value optimized out>, fp=0x42a38038) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.cpp:326 #14 0x41152046 in InvokeKernel (cx=0x46e49b00, thisv=..., fval=..., argc=<value optimized out>, argv=0xbe9402d0, rval=0xbe940410) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.cpp:381 #15 Invoke (cx=0x46e49b00, thisv=..., fval=..., argc=<value optimized out>, argv=0xbe9402d0, rval=0xbe940410) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.h:109 #16 Invoke (cx=0x46e49b00, thisv=..., fval=..., argc=<value optimized out>, argv=0xbe9402d0, rval=0xbe940410) at /Users/gal/workspace/B2G/gecko/js/src/jsinterp.cpp:414 #17 0x410f0bc6 in JS_CallFunctionValue (cx=0x46e49b00, objArg=<value optimized out>, fval=..., argc=1, argv=0xbe9402d0, rval=0xbe940410) at /Users/gal/workspace/B2G/gecko/js/src/jsapi.cpp:5758 #18 0x40c2ec70 in nsXPCWrappedJSClass::CallMethod (this=0x46e2b880, wrapper=<value optimized out>, methodIndex=<value optimized out>, info_=0x425b6928, nativeParams=0xbe9404d0) at /Users/gal/workspace/B2G/gecko/js/xpconnect/src/XPCWrappedJSClass.cpp:1432 #19 0x40c2c3f6 in nsXPCWrappedJS::CallMethod (this=0x475bae00, methodIndex=3, info=0x425b6928, params=<value optimized out>) at /Users/gal/workspace/B2G/gecko/js/xpconnect/src/XPCWrappedJS.cpp:580 #20 0x40ecc624 in PrepareAndDispatch (self=0x47b72e40, methodIndex=<value optimized out>, args=0xbe94058c) at /Users/gal/workspace/B2G/gecko/xpcom/reflect/xptcall/src/md/unix/xptcstubs_arm.cpp:105 #21 0x40ecbd8c in SharedStub () from /Users/gal/workspace/B2G/objdir-gecko/dist/bin/libxul.so #22 0x40988a8a in nsEventListenerManager::HandleEventSubType (this=<value optimized out>, aListenerStruct=<value optimized out>, aListener=0x47b72e40, aDOMEvent=0x46e931f0, aCurrentTarget=0x40379480, aPhaseFlags=6, aPusher=0xbe9406d0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventListenerManager.cpp:893 #23 0x40988bc2 in nsEventListenerManager::HandleEventInternal (this=0x482be1f0, aPresContext=<value optimized out>, aEvent=0x475ce280, aDOMEvent=0xbe9406c0, aCurrentTarget=0x40379480, aFlags=6, aEventStatus=0xbe9406c4, aPusher=0xbe9406d0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventListenerManager.cpp:966 #24 0x40998064 in nsEventListenerManager::HandleEvent (this=<value optimized out>, aVisitor=<value optimized out>, aFlags=6, ---Type <return> to continue, or q <return> to quit--- aMayHaveNewListenerManagers=<value optimized out>, aPusher=0xbe9406d0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventListenerManager.h:153 #25 nsEventTargetChainItem::HandleEvent (this=<value optimized out>, aVisitor=<value optimized out>, aFlags=6, aMayHaveNewListenerManagers=<value optimized out>, aPusher=0xbe9406d0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventDispatcher.cpp:184 #26 0x40998150 in nsEventTargetChainItem::HandleEventTargetChain (this=<value optimized out>, aVisitor=..., aFlags=6, aCallback=0x0, aMayHaveNewListenerManagers=false, aPusher=0xbe9406d0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventDispatcher.cpp:316 #27 0x409986d8 in nsEventDispatcher::Dispatch (aTarget=<value optimized out>, aPresContext=0x4aa87000, aEvent=0x475ce280, aDOMEvent=<value optimized out>, aEventStatus=0xbe940750, aCallback=0x0, aTargets=0x0) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventDispatcher.cpp:634 #28 0x409988d0 in nsEventDispatcher::DispatchDOMEvent (aTarget=0x40379480, aEvent=0x475ce280, aDOMEvent=0x46e931f0, aPresContext=0x4aa87000, aEventStatus=0xbe940750) at /Users/gal/workspace/B2G/gecko/content/events/src/nsEventDispatcher.cpp:694 #29 0x4093e930 in nsINode::DispatchEvent (this=0x40379480, aEvent=0x46e931f0, aRetVal=0xbe94078f) at /Users/gal/workspace/B2G/gecko/content/base/src/nsINode.cpp:1086 (More stack frames follow...) (gdb)
Summary: use android copybit driver in ConvertYCbCrToRGB32 and ScaleYCbCrToRGB32 → use neon fastpath in ConvertYCbCrToRGB32
This is going to need texture streaming from webgl to be really fast. I hear thats close. James, want to try the patch bug 716859? It should avoid the CPU path altogether.
Actually, no, the way the example works here, there will be still a CPU conversion. I will see if I can make the actual cubevid code smarter.
Alright, we will need both patches. The texture streaming will avoid the CPU readback in WebGL and buy us some performance, and canvas will keep hitting the CPU path here for the time being.
Comment on attachment 684409 [details] [diff] [review] Patch I am going to redo this patch a bit.
Attachment #684409 - Flags: review+ → review?
(In reply to Andreas Gal :gal from comment #12) > This is going to need texture streaming from webgl to be really fast. I hear > thats close. James, want to try the patch bug 716859? It should avoid the > CPU path altogether. I don't think that patch will get you anything -- it doesn't (observabily, afaik) modify anything other than WebGL itself, and for B2G it effectively does the same thing it does today (for now -- it sets up the stage for something smarter). Also, to texture from a video frame to webgl, you have to convert it to RGB -- we have no native YUV textures in WebGL, and we have no way to upload the raw YCbCr values to a texture (as we'd need two or three textures to do it, since the Cb/Cr channels are likely to be smaller than Y). So every time you do a texImage2D from a video file, you will hit ConvertYCbCrToRGB32 during the upload.
If the video is being decoded with the Gonk hardware decoder, the video frame will be a GonkIOSurfaceImage, which can be used as a texture directly (see ImageLayerOGL::RenderLayer). So can't we just make texImage2D copy from that texture to the destination texture? (Bonus points if we can somehow make texImage2D rebind to the GonkIOSurfaceImage texture directly without copying.)
<3 comment 17. Even without that we get rid of the read back. Agree on CPU path. The patch needs a supports_neon. Please steal if you can. Until comment 17 we should land this.
We could avoid webgl and use CSS if I could play the same source into multiple video elements without decoding multiple times.
(In reply to Andreas Gal :gal from comment #19) > We could avoid webgl and use CSS if I could play the same source into > multiple video elements without decoding multiple times. You should be able to do that using MediaStreams, e.g. video2.mozSrcObject = video1.mozCaptureStream();
Can I do it for playback?
Not sure what you mean. This demo works on desktop: http://people.mozilla.org/~roc/multi_stream.html Doesn't seem to work on my Android phone though. Maybe OOM.
Attached patch CLContext patchSplinter Review
CLContext patch, which avoids readback data from GPU in Disable out-of-process case. It can share image memory cross-thread.
WEBGL_dynamic_texture is the most optimized solution to display video stream in 3D scene. But it rely on some low level extensions, including EGL_KHR_stream, EGL_KHR_stream_consumer_gltexture and GL_NV_EGL_stream_consumer_external. As I know, ARM/Mali will support it next year.
Attached patch updated patch (obsolete) — Splinter Review
comment 23: roc, thats exactly what I need. Thanks.
Attached patch updated patchSplinter Review
Assignee: nobody → gal
Attachment #684354 - Attachment is obsolete: true
Attachment #684409 - Attachment is obsolete: true
Attachment #684665 - Attachment is obsolete: true
Attachment #684409 - Flags: review?
Attachment #684676 - Flags: review?(roc)
Attachment #684676 - Flags: review?(chris.double)
One review will do. Whoever gets up first.
I attached a CSS version of cubevid to bug 814737.
Comment on attachment 684676 [details] [diff] [review] updated patch Review of attachment 684676 [details] [diff] [review]: ----------------------------------------------------------------- I'm not the right person to review this
Attachment #684676 - Flags: review?(roc) → review?(tterribe)
Comment on attachment 684676 [details] [diff] [review] updated patch I defer to tim on this. My knowledge of neon is zero.
Attachment #684676 - Flags: review?(chris.double)
Comment on attachment 684676 [details] [diff] [review] updated patch Review of attachment 684676 [details] [diff] [review]: ----------------------------------------------------------------- This needs some work. In the future, please generate patches with at least 8 lines of context (-U8). ::: gfx/ycbcr/Makefile.in @@ +24,5 @@ > ycbcr_to_rgb565.cpp \ > $(NULL) > > +ifdef HAVE_ARM_NEON > +SSRCS += yuv2rgb8888_neon.S You should add this in the same section as yuv_row_arm.s. There's no reason to handle both files differently. @@ +93,5 @@ > endif > endif > + > +ifdef HAVE_ARM_NEON > +yuv2rgb8888_neon.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(ARM_NEON_CFLAGS) So, this doesn't work. With this current patch on Android -mfpu=neon does not show up on the compile line and I get /home/derf/src/android/mozilla-central/gfx/ycbcr/yuv_convert.cpp:93: undefined reference to `yuv420_2_rgb8888_neon' /home/derf/src/android/mozilla-central/gfx/ycbcr/yuv_convert.cpp:97: undefined reference to `yuv422_2_rgb8888_neon' You should use explicit directives in the .S file. See below. ::: gfx/ycbcr/yuv2rgb8888_neon.S @@ +1,3 @@ > +// Copyright (c) 2011 ARM Limited. All rights reserved. > +// Use of this source code is governed by a BSD-style license that can be > +// found in the LICENSE file. Do we need to update license.html for this? Where is the LICENSE file? @@ +1,4 @@ > +// Copyright (c) 2011 ARM Limited. All rights reserved. > +// Use of this source code is governed by a BSD-style license that can be > +// found in the LICENSE file. > + In order for this to work with NEON detection, you need the following directives: .arch armv7-a .fpu neon .object_arch armv4t The last one is important for producing an executable which can run on all architectures. See gfx/ycbcr/yuv_row_arm.s for an example. @@ +1,5 @@ > +// Copyright (c) 2011 ARM Limited. All rights reserved. > +// Use of this source code is governed by a BSD-style license that can be > +// found in the LICENSE file. > + > +#ifdef __ARM_NEON__ This doesn't get defined without -mfpu=neon, which you aren't using correctly (see above). @@ +98,5 @@ > + const uint8_t *y_ptr, > + const uint8_t *u_ptr, > + const uint8_t *v_ptr, > + int width, > + int height); */ This prototype is incorrect. @@ +109,5 @@ > + /* <> = height */ > + /* <> = y_pitch */ > + /* <> = uv_pitch */ > + /* <> = rgb_pitch */ > + .fnstart There are a bunch of opportunities to shave a few cycles off in various places in this function. I assume that that is not the priority here. @@ +310,5 @@ > + BGT loop_v_420 > + > + VPOP {q4-q7} > + POP {r4-r12, pc} > + .fnend Please include a .size directive so that gdb/valgrind etc., can identify this function on the callstack. @@ +464,5 @@ > + BGT loop_v_422 > + > + VPOP {q4-q7} > + POP {r4-r12, pc} > + .fnend Please include a .size directive so that gdb/valgrind etc., can identify this function on the callstack. @@ +466,5 @@ > + VPOP {q4-q7} > + POP {r4-r12, pc} > + .fnend > + > +#endif /* __ARM_NEON__ */ You need to include an ELF directive to indicate that this object does not require an executable stack in order to keep the linker from accidentally marking the stack executable for the entire program. See bug 752293 for an example. ::: gfx/ycbcr/yuv_convert.cpp @@ +44,5 @@ > + int height, > + int y_pitch, > + int uv_pitch, > + int rgb_pitch); > +#endif /* MOZILLA_MAY_SUPPORT_MMX */ This comment is wrong. @@ +88,5 @@ > +#ifdef MOZILLA_MAY_SUPPORT_NEON > + if (supports_neon()) { > + switch (yuv_type) { > + case YV12: > + yuv420_2_rgb8888_neon(rgb_buf, y_buf, u_buf, v_buf, pic_width, pic_height, This function does not support pic_width<16 and is also incorrect if either pic_width or pic_height is odd. You need to detect those cases and fall back to the C version here (or fix the function to work correctly in these cases). @@ +92,5 @@ > + yuv420_2_rgb8888_neon(rgb_buf, y_buf, u_buf, v_buf, pic_width, pic_height, > + y_pitch, uv_pitch, rgb_pitch); > + return; > + case YV16: > + yuv422_2_rgb8888_neon(rgb_buf, y_buf, u_buf, v_buf, pic_width, pic_height, This function does not support pic_width<16 and is also incorrect if pic_width is odd. You need to detect those cases and fall back to the C version here (or fix the function to work correctly in these cases).
Attachment #684676 - Flags: review?(tterribe) → review-
blocking-basecamp: --- → ?
Not sure why this was nominated but we can't block on it.
blocking-basecamp: ? → -

The bug assignee didn't login in Bugzilla in the last 7 months, so the assignee is being reset.

Assignee: gal → nobody
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: