Sorry to grave dig, but i feel this is important.
Apparently, There's a new extension for the PowerVR driver, to enable fast texture uploads. Its called "GL_IMG_texture_stream", you can find out more about it here: http://imgtec.net/forum/forum_posts.asp?TID=475 .
It seems to rely on a new kernel module and directly loading data into the driver, maybe once its more mature they will make it easier to accomplish. It may not be fully functional in the TI Driver, but I don't think we'll have to worry about this in the future. Here's some code from TI's GLESLAYER:
[codebox]
#include <sys/mman.h> // mmap()
#if defined __linux__
#define LINUX //needed for imgdefs
#endif
#include <img_types.h>
#include "bc_cat.h"
//#include <glext.h>
#include <fcntl.h>
#include "sys/ioctl.h"
#include <unistd.h>
#define BC_CAT_DRV "/dev/bc_cat"
#define MAX_BUFFERS 1
char *buf_paddr[MAX_BUFFERS];
char *buf_vaddr[MAX_BUFFERS] = { (char *) MAP_FAILED };
#define GL_TEXTURE_STREAM_IMG 0x8C0D
#define GL_TEXTURE_NUM_STREAM_DEVICES_IMG 0x8C0E
#define GL_TEXTURE_STREAM_DEVICE_WIDTH_IMG 0x8C0F
#define GL_TEXTURE_STREAM_DEVICE_HEIGHT_IMG 0x8EA0
#define GL_TEXTURE_STREAM_DEVICE_FORMAT_IMG 0x8EA1
#define GL_TEXTURE_STREAM_DEVICE_NUM_BUFFERS_IMG 0x8EA2
typedef void (GL_APIENTRYP PFNGLTEXBINDSTREAMIMGPROC) (GLint device, GLint deviceoffset);
typedef const GLubyte *(GL_APIENTRYP PFNGLGETTEXSTREAMDEVICENAMEIMGPROC) (GLenum target);
typedef void (GL_APIENTRYP PFNGLGETTEXSTREAMDEVICEATTRIBUTEIVIMGPROC) (GLenum target, GLenum pname, GLint *params);
PFNGLTEXBINDSTREAMIMGPROC myglTexBindStreamIMG = NULL;
PFNGLGETTEXSTREAMDEVICEATTRIBUTEIVIMGPROC myglGetTexStreamDeviceAttributeivIMG = NULL;
PFNGLGETTEXSTREAMDEVICENAMEIMGPROC myglGetTexStreamDeviceNameIMG = NULL;
int numBuffers, bufferWidth, bufferHeight, bufferFormat;
int bcfd = -1; //file descriptor
bc_buf_params_t bc_param;
BCIO_package ioctl_var;
void img_stream_gl_draw(int numObjects)
{
int startIndex = 0;
for(int vertical = 0;vertical < numObjects;vertical ++)
for(int horizontal = 0;horizontal < numObjects;horizontal ++)
{
//update texture here if needed
//memset(textureData);
glDrawArrays(GL_TRIANGLE_STRIP, startIndex, 4);
startIndex += 4;
}
}
int test8_init_texture_streaming()
{
const GLubyte *pszGLExtensions;
const GLubyte *pszStreamDeviceName;
int idx;
//setup driver now
if ((bcfd = open(BC_CAT_DRV, O_RDWR|O_NDELAY)) == -1) {
SGX_PERF_printf("Error opening bc driver - is bc_cat module inserted ?\n");
return 3;
}
bc_param.count = 1;
bc_param.width = inTextureWidth;
bc_param.height = inTextureHeight;
bc_param.pixel_fmt = PVRSRV_PIXEL_FORMAT_FOURCC_ORG_UYVY;
bc_param.type = BC_MEMORY_MMAP;
if (ioctl(bcfd, BCIOREQ_BUFFERS, &bc_param) != 0) {
SGX_PERF_printf("ERROR: BCIOREQ_BUFFERS failed\n");
return 4;
}
if (ioctl(bcfd, BCIOGET_BUFFERCOUNT, &ioctl_var) != 0) {
SGX_PERF_printf("Error ioctl BCIOGET_BUFFERCOUNT");
return 5;
}
if (ioctl_var.output == 0) {
SGX_PERF_printf("no buffers available from driver \n");
return 6;
}
/* Retrieve GL extension string */
pszGLExtensions = glGetString(GL_EXTENSIONS);
if (!pszGLExtensions || !strstr((char *)pszGLExtensions, "GL_IMG_texture_stream2"))
{
SGX_PERF_printf("TEST8: GL_IMG_texture_stream unsupported\n");
return 1;
}
myglTexBindStreamIMG = (PFNGLTEXBINDSTREAMIMGPROC)eglGetProcAddress("glTexBindStreamIMG");
myglGetTexStreamDeviceAttributeivIMG =
(PFNGLGETTEXSTREAMDEVICEATTRIBUTEIVIMGPROC)eglGetProcAddress("glGetTexStreamDeviceAttributeivIMG");
myglGetTexStreamDeviceNameIMG =
(PFNGLGETTEXSTREAMDEVICENAMEIMGPROC)eglGetProcAddress("glGetTexStreamDeviceNameIMG");
if(!myglTexBindStreamIMG || !myglGetTexStreamDeviceAttributeivIMG || !myglGetTexStreamDeviceNameIMG)
{
SGX_PERF_printf("TEST8: GL_IMG_texture_stream unsupported\n");
return 2;
}
pszStreamDeviceName = myglGetTexStreamDeviceNameIMG(0);
myglGetTexStreamDeviceAttributeivIMG(0, GL_TEXTURE_STREAM_DEVICE_NUM_BUFFERS_IMG, &numBuffers);
myglGetTexStreamDeviceAttributeivIMG(0, GL_TEXTURE_STREAM_DEVICE_WIDTH_IMG, &bufferWidth);
myglGetTexStreamDeviceAttributeivIMG(0, GL_TEXTURE_STREAM_DEVICE_HEIGHT_IMG, &bufferHeight);
myglGetTexStreamDeviceAttributeivIMG(0, GL_TEXTURE_STREAM_DEVICE_FORMAT_IMG, &bufferFormat);
glTexParameteri(GL_TEXTURE_STREAM_IMG, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_STREAM_IMG, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
SGX_PERF_printf("\nStream Device %s: numBuffers = %d, width = %d, height = %d, format = %x\n",
pszStreamDeviceName, numBuffers, bufferWidth, bufferHeight, bufferFormat);
for (idx = 0; idx < MAX_BUFFERS; idx++) {
ioctl_var.input = idx;
if (ioctl(bcfd, BCIOGET_BUFFERPHYADDR, &ioctl_var) != 0) {
SGX_PERF_printf("BCIOGET_BUFFERADDR: failed\n");
return 7;
}
SGX_PERF_printf("phyaddr[%d]: 0x%x\n", idx, ioctl_var.output);
buf_paddr[idx] = (char*)ioctl_var.output;
buf_vaddr[idx] = (char *)mmap(NULL, inTextureWidth*inTextureHeight*2,
PROT_READ | PROT_WRITE, MAP_SHARED,
bcfd, (long)buf_paddr[idx]);
if (buf_vaddr[idx] == MAP_FAILED) {
SGX_PERF_printf("Error: failed mmap\n");
return 8;
}
if((inTextureWidth == 160) && (inTextureHeight == 128)) //only for 256x256
memcpy(buf_vaddr[idx], yukio_160x128yuv, 160*128*2);
else
{
for (int iii= 0; iii < inTextureHeight; iii++)
memset(((char *) buf_vaddr[idx] + (inTextureWidth*iii*2)) , 0xa8, inTextureWidth*2);
}
}
return 0;
}
void test8_deinit_texture_streaming()
{
int idx;
for (idx = 0; idx < MAX_BUFFERS; idx++) {
if (buf_vaddr[idx] != MAP_FAILED)
munmap(buf_vaddr[idx], inTextureWidth*inTextureHeight*2);
}
if (bcfd > -1)
close(bcfd);
}
/* Texture streaming extension - nonEGLImage */
void test8()
{
timeval startTime, endTime;
unsigned long diffTime2;
int i;
int bufferIndex = 0;
int err;
static GLfloat texcoord_img[] =
{0,0, 1,0, 0,1, 1,1};
float angle = 0;
//initialise texture streaming
err = test8_init_texture_streaming();
if(err)
{
SGX_PERF_ERR_printf("TEST8: Init failed with err = %d\n", err);
goto deinit;
}
//initialise gl vertices
float *pVertexArray, *pTexCoordArray;
common_init_gl_vertices(inNumberOfObjectsPerSide, &pVertexArray);
common_init_gl_texcoords(inNumberOfObjectsPerSide, &pTexCoordArray);
//override the texturecoords for this extension only
glDisableVertexAttribArray(TEXCOORD_ARRAY);
glEnableVertexAttribArray(TEXCOORD_ARRAY);
glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, 0, (const void*)texcoord_img);
//override the texture binding
//glEnable(GL_TEXTURE_STREAM_IMG);
gettimeofday(&startTime, NULL);
SGX_PERF_printf("TEST8: Entering DrawArrays loop\n");
for(i = 0;(i < NUM_TEST_ITERATION)&&(!quitSignal);i ++)
{
glClear(GL_COLOR_BUFFER_BIT);
if(inRotationEnabled)
{
calculate_rotation_z(mat_z, 0);
calculate_rotation_y(mat_y, angle);
calculate_rotation_x(mat_x, 0);
matrix_mult(mat_z, mat_y, mat_temp);
matrix_mult(mat_temp, mat_x, mat_final);
glUniformMatrix4fv( matrixLocation, 1, GL_FALSE, mat_final);
angle += ANGLE_DELTA;
}
myglTexBindStreamIMG(0, bufferIndex);
img_stream_gl_draw(inNumberOfObjectsPerSide);
common_eglswapbuffers (eglDisplay, eglSurface);
}
err = glGetError();
if(err)
SGX_PERF_ERR_printf("Error in glTexBindStream loop err = %d", err);
SGX_PERF_printf("Exiting DrawArrays loop\n");
gettimeofday(&endTime, NULL);
diffTime2 = (tv_diff(&startTime, &endTime))/NUM_TEST_ITERATION;
common_log(8, diffTime2);
deinit:
test8_deinit_texture_streaming();
common_deinit_gl_vertices(pVertexArray);
}
#endif
[/codebox]