Imagination PowerVR SDK Blog

Demo using eglCreatePbufferSurface()


#1

HiÂ

I am a newbie trying to modify the trainign course demo "02_HelloTriangle" to use the eglCreatePbufferSurface() instead of eglCreateWindowSurface()

The modifications done are as follows

 EGLint s_surfaceAttribs[] =
 { EGL_WIDTH, 240,
 EGL_HEIGHT, 320,
 EGL_NONE
 };

 //eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig,(void*) m_glutWindow, NULL);
 eglSurface = eglCreatePbufferSurface(eglDisplay,eglConfig,s_surfaceAttribs);

After teh above changes i am not able to see the traingle. The output is scattered.

What changes are to be done for displaying the frame to the screen? will the eglSwapBuffers() work with pBuffer?

i am using the Imagination Technologies PowerVR SDK OVG-1.0_WINDOWS_PCEMULATION_2.04.24.0811.

thnks

RK


#2

missed out in earlier post

i hve modified the following also to be compatible for Pbuffer (added EGL_PBUFFER_BIT)

 static const int ai32ConfigAttribs[] =
 {
 EGL_RED_SIZE, 5,
 EGL_GREEN_SIZE, 6,
 EGL_BLUE_SIZE, 5,
 EGL_ALPHA_SIZE, 0,
 EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
 EGL_NONE
 };


#3

I am attaching the file after my changes

Thic works good if the macro  DRAWABLES_SIM_USING_2PBUFFER is disabled. If i enable this macro , Pbuffer is used.

If i change teh values of afClearColor,fillColor it is not refledcted in the app.

Please help me with this

Thnks

RK

/******************************************************************************

 @File OVGHelloTriangle_Glut.cpp

 @Title OpenVG Intitalization Tutorial

 @Copyright Copyright (C) Imagination Technologies Limited.

 @Platform .

 @Description Basic Tutorial that shows step-by-step how to initialize OpenVG,
 use it for drawing a line, and terminate it.

******************************************************************************/
#include "vg/openvg.h"
#include "EGL/egl.h"
#include <gl/glut.h>

// No C++ Standard Library or exception handling on Symbian platform
#include <stdio.h>
#define DRAWABLES_SIM_USING_2PBUFFER
/****************************************************************************
** Constants
****************************************************************************/
const char pszAppName[] = "OpenVG Intialization Tutorial";
int i32Frame = 0;
EGLDisplay eglDisplay = 0;
EGLSurface eglSurface = 0;
#ifdef DRAWABLES_SIM_USING_2PBUFFER
EGLSurface eglSurface1 = 0;
EGLContext eglContext = 0;
#endif
int i32WindowWidth = 240;
int i32WindowHeight= 320;

VGfloat afClearColor[4]={1.0f,0.0f,0.0f,1.0f};
VGuint fillColor= 0x00FF00FF;

VGPath vgTriangle;
VGPaint vgFillPaint;
/****************************************************************************
** Declarations
****************************************************************************/

void GlutDisplayHandler()
{
#ifdef DRAWABLES_SIM_USING_2PBUFFER
 VGint imageWidth=0;
 VGint imageHeight=0;
 VGImage image;
 int i32NumConfigs1=0;
 EGLConfig eglConfig1 = 0;
#endif
 if(i32Frame > 1000)
 exit(0);

 // Set the clear color
 vgSetfv(VG_CLEAR_COLOR, 4, afClearColor);
 // Clear the whole surface with the clear color
 vgClear(0, 0, i32WindowWidth, i32WindowHeight);
#ifdef DRAWABLES_SIM_USING_2PBUFFER
 vgFinish();


 // create a VGImage
 imageWidth = 120;
 imageHeight= 160;
 image = vgCreateImage(VG_sARGB_8888_PRE, imageWidth, imageHeight, VG_IMAGE_QUALITY_BETTER );

 static const int ai32ConfigAttribs1[] =
 {
 EGL_RED_SIZE, 5,
 EGL_GREEN_SIZE, 6,
 EGL_BLUE_SIZE, 5,
 EGL_ALPHA_SIZE, 0,
 EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
 EGL_NONE
 };
 EGLint s_surfaceAttribs1[] =
 { EGL_WIDTH, 120,
 EGL_HEIGHT, 160,
 EGL_NONE
 };


 if(!eglChooseConfig(eglDisplay, ai32ConfigAttribs1, &eglConfig1, 1, &i32NumConfigs1) || (i32NumConfigs1 != 1))
 {
 printf("Error: eglChooseConfig() failed.n");
 exit(0);
 }

 eglSurface1 = eglCreatePbufferSurface(eglDisplay,eglConfig1,s_surfaceAttribs1);

 if((eglGetError() != EGL_SUCCESS) || (eglSurface1 == EGL_NO_SURFACE))
 {
 printf("Error: eglCreateWindowSurface() failed.n");
 exit(0);
 }

 eglMakeCurrent(eglDisplay, eglSurface1, eglSurface1, eglContext);
 if(eglGetError() != EGL_SUCCESS)
 {
 printf("Error: eglMakeCurrent() failed.n");
 exit(0);
 }

 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
 vgLoadIdentity();
 vgScale((float)imageWidth, (float)imageHeight);

 vgTriangle = vgCreatePath(
 VG_PATH_FORMAT_STANDARD,
 VG_PATH_DATATYPE_F,
 1.0f, 0.0f, 4, 3,
 (unsigned int)VG_PATH_CAPABILITY_APPEND_TO);

 VGubyte aui8PathSegments[4];
 aui8PathSegments[0] = VG_MOVE_TO_ABS;
 aui8PathSegments[1] = VG_LINE_TO_ABS;
 aui8PathSegments[2] = VG_LINE_TO_ABS;
 aui8PathSegments[3] = VG_CLOSE_PATH;


 VGfloat afPoints[6];
 afPoints[0] = 0.3f;
 afPoints[1] = 0.3f;
 afPoints[2] = 0.7f;
 afPoints[3] = 0.3f;
 afPoints[4] = 0.5f;
 afPoints[5] = 0.7f;

 vgAppendPathData(vgTriangle, 4, aui8PathSegments, afPoints);


 vgRemovePathCapabilities(vgTriangle, VG_PATH_CAPABILITY_APPEND_TO);


 vgFillPaint = vgCreatePaint();
 vgSetParameteri(vgFillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
 vgSetColor(vgFillPaint, fillColor);


 vgSetfv(VG_CLEAR_COLOR, 4, afClearColor);


 // Clear the whole surface with the clear color
 vgClear(0, 0, imageWidth, imageHeight);
#endif
 // Set the current fill paint...
 vgSetPaint(vgFillPaint, VG_FILL_PATH);

 // Draw the triangle!
 vgDrawPath(vgTriangle, VG_FILL_PATH);
#ifdef DRAWABLES_SIM_USING_2PBUFFER
 vgFinish();

 vgGetPixels(image,0,0,0,0,imageWidth,imageHeight);

 vgFinish();

 vgDestroyPath(vgTriangle);

 eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
 if(eglGetError() != EGL_SUCCESS)
 {
 printf("Error: eglMakeCurrent() failed.n");
 exit(0);
 }

 eglDestroySurface(eglDisplay,eglSurface1);
 if(eglGetError() != EGL_SUCCESS)
 {
 printf("Error: eglMakeCurrent() failed.n");
 exit(0);
 }


 vgDrawImage(image);

 vgFinish();
#endif

 /*
 Drawing is double buffered, so you never see any intermediate
 results of the drawing. When you have finished drawing
 you have to call eglSwapBuffers to make the results appear on
 screen.
 */
#ifndef DRAWABLES_SIM_USING_2PBUFFER
 eglSwapBuffers(eglDisplay, eglSurface);
#endif
 glutSwapBuffers();

 ++i32Frame;
 glutPostRedisplay();
}

void CleanupOnExit()
{
 /*
 Step 6 - Destroy resources
Â




 OpenVG resources like paths and paints need to be destroyed
 when they are no longer needed.
 */
 vgDestroyPath(vgTriangle);
 vgDestroyPaint(vgFillPaint);

 // Terminate OpenVG
 eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 eglTerminate(eglDisplay);
}
/****************************************************************************
** Application entry point
****************************************************************************/
int main(int argc, char *argv[])
{
 EGLConfig eglConfig = 0;
#ifndef DRAWABLES_SIM_USING_2PBUFFER
 EGLContext eglContext = 0;
#endif
 int i32NumConfigs, i32MajorVersion, i32MinorVersion;

 /*
 Step 0 - Create a window that we can use for OpenVG output

 Window creation is platform specific so it should be done by
 a separate function.
 */

 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
 glutInitWindowSize(240, 320);
 glutInitWindowPosition(100, 100);

 int m_glutWindow = glutCreateWindow("");

 if(!m_glutWindow)
 {
 return 1;
 }

 glutDisplayFunc(GlutDisplayHandler);
 atexit(CleanupOnExit);

 /*
 Step 1 - Get the default display

 EGL uses the concept of a "display" which in most environments
 corresponds to a single physical screen. Since we usually want
 to draw to the main screen or only have a single screen to begin
 with, we let EGL pick the default display.

 Querying other displays is platform specific.
 */
 eglDisplay = (NativeDisplayType)eglGetDisplay(EGL_DEFAULT_DISPLAY);

 /*
 Step 2 - Initialize EGL

 EGL has to be initialized with the display obtained in the
 previous step. We cannot use other EGL functions except
 eglGetDisplay and eglGetError before eglInitialize has been
 called.
 If we're not interested in the EGL version number we can just
 pass NULL for the second and third parameters.
 */
 if(!eglInitialize(eglDisplay, &i32MajorVersion, &i32MinorVersion))
 {
 printf("Error: eglInitialize() failed.n");
 return 1;
 }

 /*
 Step 3 - Make OpenVG the current API

 EGL provides ways to set up OpenGL ES and OpenVG contexts
 (and possibly other graphics APIs in the future), so we need
 to specify the "current API".
 */
 eglBindAPI(EGL_OPENVG_API);

 /*
 Step 4 - Specify the required configuration attributes

 An EGL "configuration" describes the pixel format and type of
 surfaces that can be used for drawing.
 For now we just want to use a 16 bit RGB surface that is a
 window surface, i.e. it will be visible on screen. The list
 has to contain key/value pairs, terminated with EGL_NONE.
 */
 static const int ai32ConfigAttribs[] =
 {
 EGL_RED_SIZE, 5,
 EGL_GREEN_SIZE, 6,
 EGL_BLUE_SIZE, 5,
 EGL_ALPHA_SIZE, 0,
#ifndef DRAWABLES_SIM_USING_2PBUFFER
 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#else
 EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT,
#endif
 EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT,
 EGL_NONE
 };
#ifdef DRAWABLES_SIM_USING_2PBUFFER
 EGLint s_surfaceAttribs[] =
 { EGL_WIDTH, 240,
 EGL_HEIGHT, 320,
 EGL_NONE
 };
#endif
 /*
 Step 5 - Find a config that matches all requirements

 eglChooseConfig provides a list of all available configurations
 that meet or exceed the requirements given as the second
 argument. In most cases we just want the first config that meets
 all criteria, so we can limit the number of configs returned to 1.
 */
 if(!eglChooseConfig(eglDisplay, ai32ConfigAttribs, &eglConfig, 1, &i32NumConfigs) || (i32NumConfigs != 1))
 {
 printf("Error: eglChooseConfig() failed.n");
 exit(0);
 }

 /*
 Step 6 - Create a window surface to draw to

 Use the config picked in the previous step and the native window
 handle to create a window surface. A window surface is one that
 will be visible on screen inside the native window (or
 fullscreen if there is no window system).

 Pixmaps and pbuffers are surfaces which only exist in off-screen
 memory.
 */
#ifdef DRAWABLES_SIM_USING_2PBUFFER
 eglSurface = eglCreatePbufferSurface(eglDisplay,eglConfig,s_surfaceAttribs);
#else
 eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig,(void*) m_glutWindow, NULL);
#endif
 if((eglGetError() != EGL_SUCCESS) || (eglSurface == EGL_NO_SURFACE))
 {
 printf("Error: eglCreateWindowSurface() failed.n");
 exit(0);
 }

 /*
 Step 7 - Create a context

 EGL has to create a context for OpenVG. Our OpenVG resources
 like paths and images will only be valid inside this context
 (or shared contexts)
 */
 eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL);
 if((eglGetError() != EGL_SUCCESS) || (eglContext == EGL_NO_CONTEXT))
 {
 printf("Error: eglCreateContext() failed.n");
 exit(0);
 }

 /*
 Step 8 - Bind the context to the current thread and use our
 window surface for drawing and reading

 Contexts are bound to a thread. This means you don't have to
 worry about other threads and processes interfering with your
 OpenVG application.
 We need to specify a surface that will be the target of all
 subsequent drawing operations, and one that will be the source
 of read operations. They can be the same surface.
 */
 eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
 if(eglGetError() != EGL_SUCCESS)
 {
 printf("Error: eglMakeCurrent() failed.n");
 exit(0);
 }

/*
 Steps 1 to 4 - Prepare OpenVG to draw a triangle
Â


 At this point we could theoretically start drawing with OpenVG. But
 we have to specify what to draw and how to draw it first.
 */

 /*
 Step 1 - Set up a device independent coordinate system
Â


 Initially, the OpenVG coordinate system is based on the output resolution.
 To get a device independent coordinate system, we need to apply a
 transformation: Scaling by the output resolution means that coordinates
 between (0, 0) and (1, 1) will be visible on screen, with the origin
 in the lower left corner.

 Transformations are described more in-depth in the Transforms tutorial.

 It should be noted that different aspect ratios often require
 special attention regarding the layout of elements on screen.
 */

 eglQuerySurface(eglDisplay, eglSurface, EGL_WIDTH, &i32WindowWidth);
 eglQuerySurface(eglDisplay, eglSurface, EGL_HEIGHT, &i32WindowHeight);
#ifndef DRAWABLES_SIM_USING_2PBUFFER
 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
 vgLoadIdentity();
 vgScale((float)i32WindowWidth, (float)i32WindowHeight);


 /*
 Step 2 - Create a path
Â

 Drawing shapes with OpenVG requires a path which represents a series of
 line and curve segments describing the outline of the shape. The shape
 does not need to be closed, but for now we will start with a simple
 triangle.
 First we create a path handle, then we append segment and point data.

 Creating a path involves choosing a datatype used for point data (we use
 float here, indicated by VG_PATH_DATATYPE_F) and capabilities that we want
 to use. Picking the right capabilities is important as the OpenVG driver
 can use a more efficient and compact internal representation for paths
 with limited capabilities. We only need two capabilities for this tutorial:
 adding data to the path and drawing it, with the latter being implicitly
 enabled for all paths.
 */

 vgTriangle = vgCreatePath(
 VG_PATH_FORMAT_STANDARD,
 VG_PATH_DATATYPE_F,
 1.0f, 0.0f, 4, 3,
 (unsigned int)VG_PATH_CAPABILITY_APPEND_TO);

 /*
 The segments of a path are described as a series of commands, represented as
 an array of bytes. You can imagine the commands being performed by a pen:
 First the pen moves to a starting location without drawing, from there it
 draws a line to a second point. Then another line to a third point. After
 that, it closes the shape by drawing a line from the last point to the
 starting location: triangle finished!

 The suffixes _ABS and _REL attached to the commands indicate whether the
 coordinates are to be interpreted as absolute locations (seen from the
 origin)or as being relative to the location of the current point.
 */
 VGubyte aui8PathSegments[4];
 aui8PathSegments[0] = VG_MOVE_TO_ABS;
 aui8PathSegments[1] = VG_LINE_TO_ABS;
 aui8PathSegments[2] = VG_LINE_TO_ABS;
 aui8PathSegments[3] = VG_CLOSE_PATH;

 /*
 In addition to the array of commands, the path needs a list of points. A
 command can "consume" from 0 to 6 values, depending on its type. MOVE_TO
 and LINE_TO each take two values, CLOSE_PATH takes none.
 A triangle requires 3 2D vertices.
 */
 VGfloat afPoints[6];
 afPoints[0] = 0.3f;
 afPoints[1] = 0.3f;
 afPoints[2] = 0.7f;
 afPoints[3] = 0.3f;
 afPoints[4] = 0.5f;
 afPoints[5] = 0.7f;

 /*
 When appending data to the path, only the number of segments needs to be
 specified since the number of points used depends on the actual commands.
 */
 vgAppendPathData(vgTriangle, 4, aui8PathSegments, afPoints);

 /*
 Path capabilities should be removed as soon as they are no longer needed.
 The OpenVG implementation might work more efficiently if it knows that
 path data will not change since it can use an optimized internal
 representation.
 */
 vgRemovePathCapabilities(vgTriangle, VG_PATH_CAPABILITY_APPEND_TO);


 /*
 Step 3 - Create a paint
Â

 To fill a shape, we need a paint that describes how to fill it: a gradient,
 pattern, or single color. Here we choose a paint with type COLOR that
 is a simple opaque red. vgSetColor is a shortcut function that takes a
 non-premultiplied sRGBA color encoded as a 32bit integer in RGBA_8888 form.
 */
 vgFillPaint = vgCreatePaint();
 vgSetParameteri(vgFillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
 vgSetColor(vgFillPaint, fillColor);

 /*
 Step 4 - Prepare the render loop
Â


 The clear color will be used whenever calling vgClear(). The color is given
 as non-premultiplied sRGBA, represented by four float values.
 */
#endif
 // Set the clear color
 vgSetfv(VG_CLEAR_COLOR, 4, afClearColor);

 /* Enter the main glut loop to render it.*/
 glutMainLoop();

 // Say goodbye
 printf("%s finished.", pszAppName);
 return 0;
}

/*****************************************************************************
 End of file (Initialization.cpp)
*****************************************************************************/



#4

You can’t use pbuffer to display on-screen since it is off-screen buffer. If you need to use pbuffer, you must bind it into a texture so that it can be displayed on-screen.

Please see the EGL manual for more details

-Hieu