Uploading textura:
Code:
int texsize = xres*yres*4;
// kreiranje PBO buffera
glGenBuffers(MAX_PBO, &PBOBuffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, PBOBuffe);
glBufferData(GL_PIXEL_UNPACK_BUFFER_EXT, texsize, NULL, GL_STREAM_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
// kreiranje texture
glGenTextures(1, &texture);
glBindTexture(texTarget, texture); // texTarget moze biti GL_TEXTURE_2D, GL_TEXTURE_RECTANLE_EXT/ARB/NV
glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP); // stavio sam clamp, ali moze i repeat
glTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(texTarget, 0, GL_RGBA, xres, yres, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(texTarget, 0);
// Uploading texture
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, PBOBuffer);
// Prvi nacin: za sada sporiji, ali ako je driver optimizovan onda moze biti brzi
glBufferSubData(GL_PIXEL_UNPACK_BUFFER_EXT, 0, texsize, pointer);
// Drugi nacin: brzi ako se koristi specijalizovana memcopy rutina
void *Memory = glMapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY);
MyMemCopy(Memory, pointer, texsize);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_EXT);
//Treci nacin: ako CPU generise texturu tako sto sekvencijalno popunjava memoriju
//onda moze da koristis drugi nacin samo sto umesto MyMemCopy ubaci rutinu koja
//generise podatke za texturu
glBindTexture(texTarget, texture);
glTexSubImage2D(texTarget, 0, 0, 0, xres, yres, GL_BGRA, GL_UNSIGNED_BYTE, 0);
ili
// ovo bi trebalo da je brze
glTexSubImage2D(texTarget, 0, 0, 0, xres, yres, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
glBindTexture(texTarget, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
Readback:
Code:
// koristi se vise PBO buffera da bi se postigao paralelni transfer
// inicijalizacija:
#define MAX_RBPBO 2
GLuint PBOreadback[MAX_RBPBO];
int FrameSize = ViewPortSize.x * ViewPortSize.y * 4;
int FramePartSize = FrameSize / MAX_RBPBO;
// Alokacija sistemske memorije za kopiranje backbuffera
Data = (GLubyte*) malloc(m_Data, m_FrameSize);
// Inicijalizacija PBOreadback buffera
glGenBuffers(MAX_RBPBO, PBOreadback);
for (int i=0; i<MAX_RBPBO; i++)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBOreadback[i]);
glBufferData(GL_PIXEL_PACK_BUFFER_EXT, FrameSize, NULL, GL_STATIC_READ);
}
glBindBuffer(GL_PIXEL_PACK_BUFFER_EXT, 0);
// Readback code
// Zapocinje transfer iz backbuffera u PBO.
// Vodi racuna da je visina backbufera deljiva sa MAX_RBPBO,
// da ne bi doslo do greske u kopiranju
for (i=0; i<MAX_RBPBO; i++)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBOreadback[i]);
glReadPixels(0, i*ViewPortSize.y/MAX_RBPBO,
ViewPortSize.x, ViewPortSize.y / MAX_RBPBO,
GL_BGRA,
/*GL_UNSIGNED_BYTE ili*/ GL_UNSIGNED_INT_8_8_8_8_REV,
BUFFER_OFFSET(0));
}
// Kopiranje iz PBO-a u sistemsku memoriju
int i;
for (i=0; i<MAX_RBPBO; i++)
{
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, PBOreadback[i]);
// prvi nacin: koriscenjem MyMemCopy
void* pboMemory = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
MyMemCopy(FramebufferData + i*FramePartSize, pboMemory, FramePartSize);
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
// Drugi nacin: koriscenjem glGetBufferSubData
glGetBufferSubData(GL_PIXEL_PACK_BUFFER_ARB, 0,
FramePartSize, FramebufferData + i*FramePartSize);
}
Jos par sitnica... Obzirom na to da se na ovaj nacin postize asinhroni transfer podataka izmedju CPU i GPU potrebno je da modifikujes program da maksimalno paralelizujes radnje. Npr... Pre pocetka renderinga pokreni uploading texture za sledeci frame (ako mozes) ili pokreni readback na kraju frejma ali podatke iz PBO prebaci u sistemsku memoriju na pocetku sledeceg frejma. Ukratko.. ako se neki od objekata nad koji se upravo vrsi asinhroni transfer koristi u renderingu onda ce se GPU zaustaviti dok objekat ne bude spreman.
yooyo