Windowless Rendering

988 views
Skip to first unread message

Adi Shavit

unread,
Aug 28, 2014, 7:41:24 AM8/28/14
to anglep...@googlegroups.com
Hi,

  I am using FBO's for rendering to an undisplayed buffer for some basic image processing using e.g. fragment shader on a texture.
While this works fine, I still have to open a window even though nothing is displayed in it.

How can I do windowless rendering using angle?

Thanks,
Adi

Jamie Madill

unread,
Aug 28, 2014, 9:28:51 AM8/28/14
to adis...@gmail.com, anglep...@googlegroups.com
Hi Adi,

One option is an offscreen pbuffer surface to render to a texture. I'm not sure if there's any samples I have to share, but the method you'll need is called eglCreatePbufferSurface:


Maybe another option is just to hide the window? Not sure what platform you're on.


--
You received this message because you are subscribed to the Google Groups "angleproject" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angleproject...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Adi Shavit

unread,
Aug 28, 2014, 9:37:31 AM8/28/14
to anglep...@googlegroups.com, adis...@gmail.com
Hi Jamie,

  Thanks for the prompt reply.

I am in fact rendering it an off-screen FBO. I read that FBOs are preferable to pbuffers. 
On the other hand, if I understand correctly, FBOs have nothing to do directly with the EGL, whereas your suggestion is an EGL function.

I'm currently prototyping and experimenting with ANGLE on Windows with C/C++, but ultimately, targeting iOS and Android (preferably still using C/C++).
Will using eglCreatePbufferSurface avoid the need for an OS related window?

Thanks,
Adi (somewhat an OpenGL newbie)

Jamie Madill

unread,
Aug 28, 2014, 9:58:53 AM8/28/14
to adis...@gmail.com, anglep...@googlegroups.com
Hey Adi,

You could look into it and see if you can get away with rendering without using a Window. I think FBOs and having a Window would be a the solution I'd go with myself if I had a choice, as EGL stuff can be a bit arcane.

Good luck!

Adi Shavit

unread,
Aug 28, 2014, 10:16:02 AM8/28/14
to Jamie Madill, anglep...@googlegroups.com
Hi Jamie,

  Staying with the FBO was my thought too. 

Thanks a lot,
Adi

Mark Callow

unread,
Aug 28, 2014, 2:32:43 PM8/28/14
to anglep...@googlegroups.com

If ANGLE supported the EGL_KHR_surfaceless_context and GL_OES_surfaceless_context extensions then you could simply pass EGL_NO_SURFACE to eglMakeCurrent() as the read and draw surfaces. Absent that you have to create a throwaway surface, typically a 1x1 pbuffer surface, that you pass as the surface arguments to eglMakeCurrent(). The extensions were created to support exactly the use case you have.

Any chance of ANGLE supporting these?

I am in fact rendering it an off-screen FBO. I read that FBOs are preferable to pbuffers. 
On the other hand, if I understand correctly, FBOs have nothing to do directly with the EGL, whereas your suggestion is an EGL function.

Correct but you have to use EGL to create the GL context and to make that context current so making a pbuffer is only a little extra, though annoying, work.



I'm currently prototyping and experimenting with ANGLE on Windows with C/C++, but ultimately, targeting iOS and Android (preferably still using C/C++).

Android also uses EGL and recent versions may support the above extensions. So your EGL work will not be wasted.

iOS does not use EGL. It also does not have surfaces. It uses only FBO's. To get your rendering displayed on the screen a special renderbuffer must be attached to the FBO. I do not think it is necessary to create one of these special renderbuffers in order to make a context current.


Will using eglCreatePbufferSurface avoid the need for an OS related window?

Yes.

Regards

    -Mark

--
注意:この電子メールには、株式会社エイチアイの機密情報が含まれている場合が有ります。正式なメール受信者では無い場合はメール複製、 再配信または情報の使用を固く禁じております。エラー、手違いでこのメールを受け取られましたら削除を行い配信者にご連絡をお願いいたし ます.

NOTE: This electronic mail message may contain confidential and privileged information from HI Corporation. If you are not the intended recipient, any disclosure, photocopying, distribution or use of the contents of the received information is prohibited. If you have received this e-mail in error, please notify the sender immediately and permanently delete this message and all related copies.

Jamie Madill

unread,
Aug 28, 2014, 2:37:43 PM8/28/14
to callo...@artspark.co.jp, anglep...@googlegroups.com
On Thu, Aug 28, 2014 at 2:32 PM, Mark Callow <callo...@artspark.co.jp> wrote:

If ANGLE supported the EGL_KHR_surfaceless_context and GL_OES_surfaceless_context extensions then you could simply pass EGL_NO_SURFACE to eglMakeCurrent() as the read and draw surfaces. Absent that you have to create a throwaway surface, typically a 1x1 pbuffer surface, that you pass as the surface arguments to eglMakeCurrent(). The extensions were created to support exactly the use case you have.

Any chance of ANGLE supporting these?


Certainly, though we're pretty busy right now. If you're inclined we'd welcome any contributions! If you aren't up to it, you can open an issue on the tracker explaining why it'd be useful, for us to keep tabs on. It's unlikely we'd have time for it in the near or medium-term.

Thanks!
Jamie

Adi Shavit

unread,
Aug 28, 2014, 3:03:26 PM8/28/14
to anglep...@googlegroups.com
Hi Mark,

  Thanks for the suggestions. I just stated re-learning OpenGL (ES + shaders) after more than 15 years away from graphics.
Do you happen to have an example that shows what you are suggesting?

Thanks,
Adi 

Mark Callow

unread,
Aug 28, 2014, 3:44:37 PM8/28/14
to anglep...@googlegroups.com

On 2014/08/28 12:03, Adi Shavit wrote:
Hi Mark,

  Thanks for the suggestions. I just stated re-learning OpenGL (ES + shaders) after more than 15 years away from graphics.
Do you happen to have an example that shows what you are suggesting?


You previously wrote

While this works fine, I still have to open a window even though nothing is displayed in it.

So presumably you are using eglCreateWindowSurface to create that window. Just use eglCreatePbufferSurface instead. For attrib_list you'll want

EGLint attrib_list[] = {EGL _HEIGHT, 1, EGL_WIDTH, 1, 0};

Adi Shavit

unread,
Aug 29, 2014, 4:30:29 AM8/29/14
to anglep...@googlegroups.com
While this works fine, I still have to open a window even though nothing is displayed in it.
So presumably you are using eglCreateWindowSurface to create that window. Just use eglCreatePbufferSurface instead. For attrib_list you'll want

EGLint attrib_list[] = {EGL _HEIGHT, 1, EGL_WIDTH, 1, 0};

Yes, that does get used internally.
I'll see if I can just replace that.
Thanks!
Adi

 

Adi Shavit

unread,
Sep 1, 2014, 7:35:35 AM9/1/14
to anglep...@googlegroups.com
Hi Mark,

  My code is based on the sample code which uses the EGLWindow held as a unique_ptr by the SampleApplication class.
The method initializeGL() does quite a lot of stuff before the call to eglCreateWindowSurface(), so I don't really know what to do if I don't have an osWindow. What do I keep what do I toss, how do I initialize other things?

How would I modify EGLWindow::initializeGL() to do windowless rendering, say when osWindow is nullptr (or via a new initializeGL() that does not accept an osWindow ptr at all?

Thanks,
Adi

Mark Callow

unread,
Sep 8, 2014, 6:57:43 PM9/8/14
to anglep...@googlegroups.com

On 2014/09/01 4:35, Adi Shavit wrote:
Hi Mark,

  My code is based on the sample code which uses the EGLWindow held as a unique_ptr by the SampleApplication class.
The method initializeGL() does quite a lot of stuff before the call to eglCreateWindowSurface(), so I don't really know what to do if I don't have an osWindow. What do I keep what do I toss, how do I initialize other things?

How would I modify EGLWindow::initializeGL() to do windowless rendering, say when osWindow is nullptr (or via a new initializeGL() that does not accept an osWindow ptr at all?

Sorry for the delay. I was on vacation.

osWindow is only needed for getting the EGLDisplay to pass to eglInitialize, which is an EGL extension, and for creating a window surface. In theory the eglGetPlatformDisplayEXT stuff should not be needed and you should be able to start your initialization code with

if (!eglInitialize(EGL_DEFAULT_DISPLAY, &majorVersion, &minorVersion)) {
  ...

Whether the theory holds true for ANGLE's EGL I do not know.

You can then replace

const EGLint surfaceAttributes[] =
{
  EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_TRUE, // Why does ANGLE's sample require an NVIDIA extension?
  EGL_NONE, EGL_NONE,
};

mSurface = eglCreateWindowSurface(mDisplay, mConfig, osWindow->getNativeWindow(), surfaceAttributes);

with 

const EGLint pbufferAttributes[] = {
  EGL _HEIGHT, 1,
  EGL_WIDTH, 1,
  EGL_NONE,
};
mSurface = eglCreatePbufferSurface(mDisplay, mconfig, pbufferAttributes);

Depending on what else your application is doing, it may or may not need an OS window. That is a separate issue from windowless rendering. E.g, you'll need one if you want handle mouse or touch input or need to display something other than text.

Adi Shavit

unread,
Sep 9, 2014, 1:54:17 AM9/9/14
to anglep...@googlegroups.com
Hi,

Sorry for the delay. I was on vacation.

No worries :-)
 

osWindow is only needed for getting the EGLDisplay to pass to eglInitialize, which is an EGL extension, and for creating a window surface. In theory the eglGetPlatformDisplayEXT stuff should not be needed and you should be able to start your initialization code with

if (!eglInitialize(EGL_DEFAULT_DISPLAY, &majorVersion, &minorVersion)) {
  ...

Whether the theory holds true for ANGLE's EGL I do not know.

Yeah, this fails.
Given that EGL_DEFAULT_DISPLAY == EGL_NO_DISPLAY == ((EGLDisplay)0) the code in eglInitialize() looks like this:

    if (dpy == EGL_NO_DISPLAY)

    {

        return egl::error(EGL_BAD_DISPLAY, EGL_FALSE);

    }

So it returns immediately.
Later calls also fails if I ignore the error.

Regards,
Adi
 

Shannon Woods

unread,
Sep 9, 2014, 11:29:09 AM9/9/14
to anglep...@googlegroups.com
You need to retrieve a default display from EGL before passing it to eglInitialize, by calling

EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

You should then be able to pass that display to eglInitialize() without issue. EGL_DEFAULT_DISPLAY is technically of type EGLNativeDisplayType, and functions as a display ID, rather than a display itself (which would be of type EGLDisplay), and doesn't satisfy the specification's requirement that the display argument refer to a valid EGLDisplay.

-- Shannon --

Adi Shavit

unread,
Sep 10, 2014, 2:28:15 AM9/10/14
to shanno...@chromium.org, anglep...@googlegroups.com
Hi Shannon,

  Thanks!! That got it to work.
For completeness and future reference, here's what I did to get it to work (though some refactoring might be a good idea).
I added a new method, bool EGLWindow::initializeGL() that does not accept an OSWindow argument.
This is the implementation:


bool EGLWindow::initializeGL()
{
   mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   if (mDisplay == EGL_NO_DISPLAY)
   {
      destroyGL();
      return false;
   }

   EGLint majorVersion, minorVersion;
   if (!eglInitialize(mDisplay, &majorVersion, &minorVersion))
   {
      destroyGL();
      return false;
   }

   eglBindAPI(EGL_OPENGL_ES_API);
   if (eglGetError() != EGL_SUCCESS)
   {
      destroyGL();
      return false;
   }

   const EGLint configAttributes[] =
   {
      EGL_RED_SIZE, 8,
      EGL_GREEN_SIZE, 8,
      EGL_BLUE_SIZE, 8,
      EGL_ALPHA_SIZE, 8,
      EGL_DEPTH_SIZE, 24,
      EGL_STENCIL_SIZE, 8,
      EGL_SAMPLE_BUFFERS, EGL_DONT_CARE,
      EGL_NONE
   };

   EGLint configCount;
   if (!eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount) || (configCount != 1))
   {
      destroyGL();
      return false;
   }

   const EGLint pbufferAttributes[] = 
   {
      EGL_HEIGHT, 1,
      EGL_WIDTH, 1,
      EGL_NONE,
   };
   mSurface = eglCreatePbufferSurface(mDisplay, mConfig, pbufferAttributes);
   if (mSurface == EGL_NO_SURFACE)
   {
      eglGetError(); // Clear error and try again
      mSurface = eglCreateWindowSurface(mDisplay, mConfig, NULL, NULL);
   }

   if (eglGetError() != EGL_SUCCESS)
   {
      destroyGL();
      return false;
   }

   EGLint contextAttibutes[] =
   {
      EGL_CONTEXT_CLIENT_VERSION, mClientVersion,
      EGL_NONE
   };
   mContext = eglCreateContext(mDisplay, mConfig, NULL, contextAttibutes);
   if (eglGetError() != EGL_SUCCESS)
   {
      destroyGL();
      return false;
   }

   eglMakeCurrent(mDisplay, mSurface, mSurface, mContext);
   if (eglGetError() != EGL_SUCCESS)
   {
      destroyGL();
      return false;
   }

   // Turn off vsync
   eglSwapInterval(mDisplay, 0);

   return true;
}

The main changes from EGLWindow::initializeGL(const OSWindow *osWindow) are highlighted.
Thanks!
Adi

 


--
You received this message because you are subscribed to a topic in the Google Groups "angleproject" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angleproject/VsiiLl9vuD8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angleproject...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages