List items
Items from the current list are shown below.
Blog
29 Jun 2024 : Day 273 #
Continuing on with our investigation from yesterday, we've got a WebView that now runs but doesn't render. Today I need to find out the reason. The good news is that the WebGL on this build is still working, so we're definitely getting closer.
If you've been following along you'll know that this isn't the first time I've needed to get the WebView render pipeline working. The difference is that this time I have the delta between where we are now and where there's a working WebView, I just need to tread carefully enough between here and there so as not to destroy the WebGL in the process.
So, first up, why is the WebView not working. From what we saw yesterday I already know that this is bounded by a broken call to GLContextProvider::CreateOffscreen() which is returning null. I want to step through the code to find out why.
Last night I couldn't do this because I only had a partial build (meaning the debug symbols and source were misaligned with the binary). I ran a build overnight to fix that. So now it's time to step through.
I've placed a breakpoint on CompositorOGL::CreateContext(). Let's see what we can see when we step through the code from there. Keep in mind that we're interested in the call to CreateOffscreen() and what it's returning.
It's hard to tell from the debug trace, but the line that's failing is the following:
To help with this I've set a bunch of breakpoints that will allow me to skip between the relevant parts of the code:
Once again, we hit all of the breakpoints in order before we get there. There are more of them this time:
This results in the overall method returning early with an error. Is it a real error though? It might be interesting to find out what happens if we force the code to ignore the error and continue on regardless.
But when I forcefully clear the error value using the debugger, I still don't get rendering. There's no crash, but there's also no web page: just a blank screen.
So the question I want to now answer is "Why is IsFramebufferComplete() returning false?". It's worth checking what the method does.
I'm going to look into this further, but it's the end of the day here, so I'll have to pick this up again tomorrow.
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
If you've been following along you'll know that this isn't the first time I've needed to get the WebView render pipeline working. The difference is that this time I have the delta between where we are now and where there's a working WebView, I just need to tread carefully enough between here and there so as not to destroy the WebGL in the process.
So, first up, why is the WebView not working. From what we saw yesterday I already know that this is bounded by a broken call to GLContextProvider::CreateOffscreen() which is returning null. I want to step through the code to find out why.
Last night I couldn't do this because I only had a partial build (meaning the debug symbols and source were misaligned with the binary). I ran a build overnight to fix that. So now it's time to step through.
I've placed a breakpoint on CompositorOGL::CreateContext(). Let's see what we can see when we step through the code from there. Keep in mind that we're interested in the call to CreateOffscreen() and what it's returning.
Thread 38 "Compositor" hit Breakpoint 1, mozilla::layers:: CompositorOGL::CreateContext (this=this@entry=0x7ed4002ed0) at gfx/layers/opengl/CompositorOGL.cpp:227 227 already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() { (gdb) n 231 nsIWidget* widget = mWidget->RealWidget(); (gdb) n 232 void* widgetOpenGLContext = (gdb) n 234 if (widgetOpenGLContext) { (gdb) n 248 if (!context && gfxEnv::LayersPreferOffscreen()) { (gdb) n 249 nsCString discardFailureId; (gdb) n 257 context = GLContextProvider::CreateOffscreen( (gdb) p context $1 = {mRawPtr = 0x0} (gdb) s mozilla::gl::GLContextProviderEGL::CreateOffscreen (size=..., flags=flags@entry=mozilla::gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE, out_failureId=out_failureId@entry=0x7f1f96b1c8) at gfx/gl/GLContextProviderEGL.cpp:1264 1264 gl = CreateHeadless({CreateContextFlags::REQUIRE_COMPAT_PROFILE}, out_failureId); (gdb) p gl $2 = {mRawPtr = 0x0} (gdb) n 1267 if (!gl || !gl->IsOffscreenSizeAllowed(size)) { (gdb) p gl $3 = {mRawPtr = 0x7ed419ee40} (gdb) n 1271 UniquePtr<GLScreenBuffer> newScreen = GLScreenBuffer::Create(gl, size); (gdb) p size $4 = (const mozilla::gfx::IntSize &) @0x7ed4002fc4: {<mozilla::gfx:: BaseSize<int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits> >> = {{{ width = 1080, height = 2520}, components = {1080, 2520}}}, <mozilla:: gfx::UnknownUnits> = {<No data fields>}, <No data fields>} (gdb) n 1272 if ((!newScreen) || (!newScreen->Resize(size))) { (gdb) p newScreen.mTuple.mFirstA $6 = (mozilla::gl::GLScreenBuffer *) 0x7ed4003ba0 (gdb) n 1271 UniquePtr<GLScreenBuffer> newScreen = GLScreenBuffer::Create(gl, size); (gdb) n 1262 RefPtr<GLContext> gl; (gdb) n mozilla::layers::CompositorOGL::CreateContext (this=this@entry=0x7ed4002ed0) at gfx/layers/opengl/CompositorOGL.cpp:249 249 nsCString discardFailureId; (gdb) n 263 if (!context) { (gdb) p context $7 = {mRawPtr = 0x0} (gdb)As we can see from this, we drop in to the CreateOffscreen() method. This calls CreateHeadless() which gives us what appears to be a valid context. Then we get a call to GLScreenBuffer::Create() which gives us a valid GLScreenBuffer object.
It's hard to tell from the debug trace, but the line that's failing is the following:
if ((!newScreen) || (!newScreen->Resize(size)))We can see from the trace that newScreen is valid, so it's the call to Resize() which is returning false. We can't yet tell why. But we can find out by stepping inside the Resize() method to check. That'll require us to re-run the application. Let's give that a go.
To help with this I've set a bunch of breakpoints that will allow me to skip between the relevant parts of the code:
(gdb) info break Num Type Disp Enb Address What 3 breakpoint keep y 0x0000007ff11988a4 in mozilla::layers:: CompositorOGL::CreateContext() at gfx/layers/opengl/ CompositorOGL.cpp:227 breakpoint already hit 1 time 4 breakpoint keep y 0x0000007ff1131540 in mozilla::gl:: GLContextProviderEGL::CreateOffscreen(mozilla::gfx::IntSizeTyped<mozilla:: gfx::UnknownUnits> const&, mozilla::gl::CreateContextFlags, nsTSubstring<char>*) at gfx/gl/ GLContextProviderEGL.cpp:1260 breakpoint already hit 1 time 5 breakpoint keep y 0x0000007ff1107644 in mozilla::gl:: GLScreenBuffer::Resize(mozilla::gfx::IntSizeTyped<mozilla::gfx:: UnknownUnits> const&) at gfx/gl/GLScreenBuffer.cpp: 339 breakpoint already hit 1 time 6 breakpoint keep y 0x0000007ff110695c in mozilla::gl:: GLScreenBuffer::Attach(mozilla::gl::SharedSurface*, mozilla::gfx:: IntSizeTyped<mozilla::gfx::UnknownUnits> const&) at gfx/gl/GLScreenBuffer.cpp: 275 (gdb)Now let's step through, hitting these breakpoints as we go, and take special care not to jump past the Resize() call.
Thread 37 "Compositor" hit Breakpoint 3, mozilla::layers:: CompositorOGL::CreateContext (this=this@entry=0x7ed8002f10) at gfx/layers/opengl/CompositorOGL.cpp:227 227 already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 4, mozilla::gl:: GLContextProviderEGL::CreateOffscreen (size=..., flags=flags@entry=mozilla::gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE, out_failureId=out_failureId@entry=0x7f179ac1c8) at gfx/gl/GLContextProviderEGL.cpp:1260 1260 CreateContextFlags flags, nsACString* const out_failureId) { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 5, mozilla::gl::GLScreenBuffer:: Resize (this=0x7ed8003ba0, size=...) at gfx/gl/GLScreenBuffer.cpp:339 339 bool GLScreenBuffer::Resize(const gfx::IntSize& size) {That's all of our breakpoints hit. We're now at the start of the Resize() method. Let's step through it.
339 bool GLScreenBuffer::Resize(const gfx::IntSize& size) { (gdb) n 342 if (!newBack) return false; (gdb) p mFactory.mTuple->mFirstA $15 = (mozilla::gl::SurfaceFactory *) 0x7ed8004190 (gdb) p newBack.mRawPtr $17 = (mozilla::layers::SharedSurfaceTextureClient *) 0x7ed81af430 (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 6, mozilla::gl::GLScreenBuffer:: Attach (this=this@entry=0x7ed8003ba0, surf=0x7ed81a1c80, size=...) at gfx/gl/GLScreenBuffer.cpp:275 275 bool GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size) {Now we're inside the Attach() method. Let's step through this.
275 bool GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size) { (gdb) n 276 ScopedBindFramebuffer autoFB(mGL); (gdb) p size $18 = (const mozilla::gfx::IntSize &) @0x7ed8003004: {<mozilla::gfx:: BaseSize<int, mozilla::gfx::IntSizeTyped<mozilla::gfx::UnknownUnits> >> = {{{ width = 1080, height = 2520}, components = {1080, 2520}}}, <mozilla:: gfx::UnknownUnits> = {<No data fields>}, <No data fields>} (gdb) n 278 const bool readNeedsUnlock = (mRead && SharedSurf()); (gdb) n 283 surf->LockProd(); (gdb) n 285 if (mRead && size == Size()) { (gdb) p mRead.mTuple.mFirstA $20 = (mozilla::gl::ReadBuffer *) 0x0 (gdb) n 289 UniquePtr<ReadBuffer> read = ReadBuffer::Create(mFactory->mDesc.gl, surf); (gdb) n 291 if (!read) { (gdb) n 292 surf->UnlockProd(); (gdb) p read.mTuple.mFirstA $22 = (mozilla::gl::ReadBuffer *) 0x0 (gdb)So read is null and that must be because ReadBuffer::Create() is returning null. We need to find out why and the same drill applies: place a breakpoint on ReadBuffer::Create() and step through the code to try to figure out where it's failing.
Once again, we hit all of the breakpoints in order before we get there. There are more of them this time:
Thread 37 "Compositor" hit Breakpoint 3, mozilla::layers:: CompositorOGL::CreateContext (this=this@entry=0x7ee0002f10) at gfx/layers/opengl/CompositorO GL.cpp:227 227 already_AddRefed<mozilla::gl::GLContext> CompositorOGL::CreateContext() { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 4, mozilla::gl:: GLContextProviderEGL::CreateOffscreen (size=..., flags=flags@entry=mozilla::gl::CreateContextFlags::REQUIRE_COMPAT_PROFILE, out_failureId=out_failureId@entry=0x7f1f98d1c8) at gfx/gl/GLContextProviderEGL.c pp:1260 1260 CreateContextFlags flags, nsACString* const out_failureId) { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 5, mozilla::gl::GLScreenBuffer:: Resize (this=0x7ee0003bc0, size=...) at gfx/gl/GLScreenBuffer.cpp:339 339 bool GLScreenBuffer::Resize(const gfx::IntSize& size) { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 6, mozilla::gl::GLScreenBuffer:: Attach (this=this@entry=0x7ee0003bc0, surf=0x7ee01a1ca0, size=...) at gfx/gl/GLScreenBuffer.cpp:275 275 bool GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size) { (gdb) c Continuing. Thread 37 "Compositor" hit Breakpoint 7, mozilla::gl::ReadBuffer:: Create (gl=0x7ee019ee60, surf=surf@entry=0x7ee01a1ca0) at gfx/gl/GLScreenBuffer.cpp:358 358 UniquePtr<ReadBuffer> ReadBuffer::Create(GLContext* gl, SharedSurface* surf) {Now we're in the right place. Let's step through the ReadBuffer::Create() method to find out what's going wrong.
358 UniquePtr<ReadBuffer> ReadBuffer::Create(GLContext* gl, SharedSurface* surf) { (gdb) n 361 GLContext::LocalErrorScope localError(*gl); (gdb) n 366 colorTex = surf->ProdTexture(); (gdb) n 367 target = surf->ProdTextureTarget(); (gdb) n 370 GLuint fb = 0; (gdb) n 371 gl->fGenFramebuffers(1, &fb); (gdb) n 372 gl->AttachBuffersToFB(colorTex, 0, 0, 0, fb, target); (gdb) p fb $38 = 2 (gdb) p target $39 = 3553 (gdb) n 374 UniquePtr<ReadBuffer> ret(new ReadBuffer(gl, fb, 0, 0, surf)); (gdb) n 376 GLenum err = localError.GetError(); (gdb) p ret.mTuple.mFirstA $41 = (mozilla::gl::ReadBuffer *) 0x7ee01a16e0 (gdb) n 378 if (err) return nullptr; (gdb) p err $42 = 0 (gdb) n 381 if (needsAcquire) { (gdb) p needsAcquire $43 = 255 (gdb) n 382 surf->ProducerReadAcquire(); (gdb) n 384 const bool isComplete = gl->IsFramebufferComplete(fb); (gdb) n 386 surf->ProducerReadRelease(); (gdb) p isComplete $44 = false (gdb) set isComplete=true (gdb) p isComplete $45 = true (gdb) n 389 if (!isComplete) return nullptr; (gdb) n 374 UniquePtr<ReadBuffer> ret(new ReadBuffer(gl, fb, 0, 0, surf)); (gdb) n 361 GLContext::LocalErrorScope localError(*gl); (gdb) c Continuing.Starting at the top, we can see that it's creating the buffers. It generates a framebuffer, then a ReadBuffer; this all appears to work fine. Then it acquires the buffer. Then things start to go wrong. A check is made to see whether the frame buffer is complete, but the result comes back negative.
This results in the overall method returning early with an error. Is it a real error though? It might be interesting to find out what happens if we force the code to ignore the error and continue on regardless.
But when I forcefully clear the error value using the debugger, I still don't get rendering. There's no crash, but there's also no web page: just a blank screen.
So the question I want to now answer is "Why is IsFramebufferComplete() returning false?". It's worth checking what the method does.
bool GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) { MOZ_ASSERT(fb); ScopedBindFramebuffer autoFB(this, fb); MOZ_GL_ASSERT(this, fIsFramebuffer(fb)); GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (pStatus) *pStatus = status; return status == LOCAL_GL_FRAMEBUFFER_COMPLETE; }The call to the ScopedBindFramebuffer constructor will bind the framebuffers using the Init() method:
ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL) : mGL(aGL) { Init(); } /* ScopedBindFramebuffer - Saves and restores with GetUserBoundFB and * BindUserFB. */ void ScopedBindFramebuffer::Init() { if (mGL->IsSupported(GLFeature::split_framebuffer)) { mOldReadFB = mGL->GetReadFB(); mOldDrawFB = mGL->GetDrawFB(); } else { mOldReadFB = mOldDrawFB = mGL->GetFB(); } }So IsFramebufferComplete() is essentially calling fCheckFramebufferStatus() on the bound framebuffer. Maybe we can find out what the error status is from the value returned by fCheckFramebufferStatus(). That might help. Back to the top of the method we go.
Thread 37 "Compositor" hit Breakpoint 7, mozilla::gl::ReadBuffer:: Create (gl=0x7ee019ee40, surf=surf@entry=0x7ee01a1c80) at gfx/gl/GLScreenBuffer.cpp:358 358 UniquePtr<ReadBuffer> ReadBuffer::Create(GLContext* gl, SharedSurface* surf) { (gdb) n 361 GLContext::LocalErrorScope localError(*gl); (gdb) n 366 colorTex = surf->ProdTexture(); (gdb) n 367 target = surf->ProdTextureTarget(); (gdb) n 370 GLuint fb = 0; (gdb) n 371 gl->fGenFramebuffers(1, &fb); (gdb) n 372 gl->AttachBuffersToFB(colorTex, 0, 0, 0, fb, target); (gdb) n Thread 37 "Compositor" hit Breakpoint 11, mozilla::gl:: ScopedBindFramebuffer::ScopedBindFramebuffer (this=0x7f1f9db048, aGL=0x7ee019ee40, aNewFB=2) at gfx/gl/ScopedGLHelpers.cpp:60 60 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB) (gdb) n 62 Init(); (gdb) n 63 mGL->BindFB(aNewFB); (gdb) n mozilla::gl::GLContext::AttachBuffersToFB (this=this@entry=0x7ee019ee40, colorTex=colorTex@entry=0, colorRB=colorRB@entry=0, depthRB=depthRB@entry=0, stencilRB=stencilRB@entry=0, fb=<optimized out>, target=target@entry=3553) at gfx/gl/GLContext.cpp:1755 1755 if (colorTex) { (gdb) n 1761 } else if (colorRB) { (gdb) n 1769 if (depthRB) { (gdb) n 1776 if (stencilRB) { (gdb) n mozilla::gl::ReadBuffer::Create (gl=0x7ee019ee40, surf=surf@entry=0x7ee01a1c80) at gfx/gl/GLScreenBuffer.cpp:374 374 UniquePtr<ReadBuffer> ret(new ReadBuffer(gl, fb, 0, 0, surf)); (gdb) n 376 GLenum err = localError.GetError(); (gdb) n 378 if (err) return nullptr; (gdb) n 381 if (needsAcquire) { (gdb) n 382 surf->ProducerReadAcquire(); (gdb) n 384 const bool isComplete = gl->IsFramebufferComplete(fb); (gdb) s Thread 37 "Compositor" hit Breakpoint 9, mozilla::gl::GLContext:: IsFramebufferComplete (this=this@entry=0x7ee019ee40, fb=2, pStatus=pStatus@entry=0x0) at gfx/gl/GLContext.cpp:1734 1734 bool GLContext::IsFramebufferComplete(GLuint fb, GLenum* pStatus) { (gdb) n 1737 ScopedBindFramebuffer autoFB(this, fb); (gdb) s Thread 37 "Compositor" hit Breakpoint 11, mozilla::gl:: ScopedBindFramebuffer::ScopedBindFramebuffer (this=0x7f1f9db048, aGL=0x7ee019ee40, aNewFB=2) at gfx/gl/ScopedGLHelpers.cpp:60 60 ScopedBindFramebuffer::ScopedBindFramebuffer(GLContext* aGL, GLuint aNewFB) (gdb) n 62 Init(); (gdb) p mOldReadFB $46 = 530428000 (gdb) p mOldDrawFB $47 = 127 (gdb) n 63 mGL->BindFB(aNewFB); (gdb) p aNewFB $48 = 2 (gdb) p mGL $49 = (mozilla::gl::GLContext * const) 0x7ee019ee40 (gdb) n mozilla::gl::GLContext::IsFramebufferComplete (this=this@entry=0x7ee019ee40, fb=<optimized out>, pStatus=pStatus@entry=0x0) at gfx/gl/GLContext.cpp:1740 1740 GLenum status = fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); (gdb) n 1741 if (pStatus) *pStatus = status; (gdb) p status $50 = 36055 (gdb) p/x status $51 = 0x8cd7 (gdb)So we have an error value coming back from fCheckFramebufferStatus() of 0x8cd7. Checking the documentation and the GLConsts.h file, we can see that the error returned is the following:
#define LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7And checking the docs, it tells us that:
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT is returned if the framebuffer does not have at least one image attached to it.
I'm going to look into this further, but it's the end of the day here, so I'll have to pick this up again tomorrow.
If you'd like to read any of my other gecko diary entries, they're all available on my Gecko-dev Diary page.
Comments
Uncover Disqus comments