PDA

View Full Version : PBO for streaming textures



Mars_999
07-09-2008, 09:41 PM
Anyone here done it?




TextureLoader texture;
unsigned int pboBuffer = 0;
unsigned int arrayDepth = filenames.size();

glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, GetId(arrayName));
glGenBuffers(1, &pboBuffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pboBuffer);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_R, GL_REPEAT);
glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_RGBA8, 64, 64, 4, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);

for(int i = 0; i < arrayDepth; ++i)
{
texture.Load(filenames[i]);
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, texture.imageSize, NULL, GL_STREAM_DRAW);
void* pboMemory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
memcpy(pboMemory, texture.imageData, texture.imageSize);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, 0, 0, i, 64, 64, 1, GL_BGRA, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glDeleteBuffers(1, &amp;pboBuffer);
return true;


Because its not working for me... ;(

Dark Photon
07-10-2008, 06:36 AM
Anyone here done it?
Yep.


Because its not working for me... ;(
Not working, or not working fast. I'd expect the latter, because you're loading your file from disk in the same loop as you're doing the upload. Using PBOs is useless here. With that disk load in the loop, just use glTexImage#D with a CPU-side memory pointer and be done with it.

songho
07-10-2008, 11:17 AM
If you meant the performance issue in your code, then I see an unnecessary memory copy in your code:
file -> system memory -> PBO -> GL texture

memcpy() between system memory and a PBO should be avoided to increase the performance. I don't see any advantage in the above path, and even it is slower than the conventional way without PBO:
file -> system memory -> GL texture

The ideal way to improve the data transfer rate is loading the texture source from file to a PBO directly:
file -> PBO -> GL texture

In this path, it significantly increases the texture upload performance by 2 reasons:

1. DMA (Direct Memory Access)
OpenGL (GPU) can transfer the pixel data from a PBO to a texture object through DMA without wasting CPU cycles. (CPU still involves in the texture loading from the file to a PBO, but, CPU is free between PBO and texture.)

2. Asynchronous
OpenGL may put aside this DMA transfer for later execution, so, OpenGL pixel operation calls such as, glTexSubImage2D(), can return immediately. Therefore, CPU can process other jobs without waiting the actual texture copy.

Mars_999
07-10-2008, 05:01 PM
What I am seeing is the mipmapping isn't working with it. I use glGenerateMipmapsEXT and I get white textures.

Mars_999
07-10-2008, 08:10 PM
Here is the improved code I am now moving from file to PBO as suggested but still doesn't work? Anyone see what maybe wrong?

Thanks



GenerateTexture2DArrayPBO(std::vector<std::string>&amp; filenames, int wrapMode, bool flag, unsigned int textureSize,
unsigned int textureChannels, std::string&amp; arrayName)
{
unsigned int pboBuffer = 0;
unsigned int imageTypeFormat = 0, imageTypeInternal = 0;
unsigned int arrayDepth = filenames.size();
void* pboMemory = NULL;

bool bgr = CheckChannelOrder(filenames.at(0));
switch(textureChannels * 8)
{
case 8:
imageTypeFormat = GL_LUMINANCE;
imageTypeInternal = flag ? GL_COMPRESSED_LUMINANCE : GL_LUMINANCE8;
break;

case 16:
break;

case 24:
imageTypeFormat = bgr ? GL_BGR : GL_RGB;
imageTypeInternal = flag ? GL_COMPRESSED_RGB_S3TC_DXT1_EXT : GL_RGB8;
break;

case 32:
imageTypeFormat = bgr ? GL_BGRA :GL_RGBA;
imageTypeInternal = flag ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_RGBA8;
break;

default:
break;
}

glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, imageTypeInternal, 64, 64, arrayDepth, 0, imageTypeFormat, GL_UNSIGNED_BYTE, NULL);
glGenBuffers(1, &amp;pboBuffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pboBuffer);
glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, GetId(arrayName));
if(gameSetupData.enableMipmaps)
{
glGenerateMipmapEXT(GL_TEXTURE_2D_ARRAY_EXT);
//glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_GENERATE_MIPMAP, GL_TRUE);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
else
{
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, wrapMode);
glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_R, wrapMode);

for(int i = 0; i < arrayDepth; ++i)
{
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, 64*64*textureChannels, NULL, GL_STREAM_DRAW);
pboMemory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
LoadTGAFile(filenames[i].c_str(), pboMemory);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, 0, 0, i, 64, 64, 1,
imageTypeFormat, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
glDeleteBuffers(1, &amp;pboBuffer);
if(gameSetupData.enableMipmaps)
glGenerateMipmapEXT(GL_TEXTURE_2D_ARRAY_EXT);

return true;
}

bool LoadTGAFile(const char *filename, void* pboMemory)
{
unsigned char TGAheader[12] = {0,0,2,0,0,0,0,0,0,0,0,0}; // Uncompressed TGA Header
unsigned char TGAcompare[12] = {0}; // Used To Compare TGA Header
unsigned char header[6] = {0}; // First 6 Useful Bytes From The Header
unsigned int bytesPerPixel = 0; // Holds Number Of Bytes Per Pixel Used In The TGA File
unsigned int bpp = 0; // Hold number of bits per pixel
unsigned int temp = 0; // Temporary Variable
unsigned int imageSize = 0;
unsigned int imageWidth = 0, imageHeight = 0;

FILE *file = fopen(filename, "rb"); // Open The TGA File

if(file == NULL ||
fread(TGAcompare, 1, sizeof(TGAcompare), file) != sizeof(TGAcompare) ||
memcmp(TGAheader, TGAcompare, sizeof(TGAheader)) != 0 || fread(header, 1, sizeof(header), file) != sizeof(header))
{
if(file == NULL)
{
//kill app here
return false;
}
else
{
//kill app here
fclose(file);
return false;
}
}

imageWidth = header[1] * 256 + header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
imageHeight = header[3] * 256 + header[2]; // Determine The TGA Height (highbyte*256+lowbyte)

if(imageWidth <= 0 || imageHeight <= 0 || (header[4] != 24 &amp;&amp; header[4] != 32))
{
//kill app here
fclose(file);
return false;
}

bpp = header[4];// Grab The TGA's Bits Per Pixel (24 or 32)
bytesPerPixel = bpp / 8;// Divide By 8 To Get The Bytes Per Pixel
imageSize = imageWidth * imageHeight * bytesPerPixel;// Calculate The Memory Required For The TGA Data
if(fread(pboMemory, 1, imageSize, file) != imageSize)
{
//kill app here
fclose(file);
return false;
}
fclose(file);
return true;
}

songho
07-10-2008, 09:53 PM
glTexSubImage2D() will trigger automatic mipmaps generation, if GL_GENERATE_MIPMAP is once set to GL_TRUE.

So, I believe that calling glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE) is better than the manual mipmap generation with glGenerateMipmapEXT().

Please test once again with only the base level texture after disabling all mipmapping settings of your system in order to see if it is mipmapping problem.

Mars_999
07-11-2008, 03:48 AM
I already tried GL_GENERATE_MIPMAP and still doesn't work. I even tried manually setting the mipmap chain for each level with glGenerateMipmapsEXT and still nothing.

Mars_999
07-16-2008, 11:51 AM
Ok, the problem is its a bug, as of driver 175.19 on Vista 64bit, and Nvidia is working on fixing it.

ruysch
08-25-2008, 04:01 PM
I am using the exact same driver and I get very performance with PBO texture transfer. (its actually alot better to transfer the texture in the *normal* way)

Is there any word on when a improved driver will be made public?