There are some things you can do, though how much you can benefit from them depends on the circumstances.
First, make sure that your pixel upload format is correct for the driver's needs. You seem to have that taken care of with GL_BGRA, GL_UNSIGNED_BYTE
, which is likely the driver's preferred format for GL_RGBA8
image formats.
However, if you happen to have access to OpenGL 4.3 or a driver that implements ARB_internalformat_query2, you can actually detect at runtime what the preferred upload format will be. Like this:
GLint pixelFormat, pixelType;
glGetInternalFormativ(GL_TEXTURE_2D, GL_RGBA8, GL_TEXTURE_IMAGE_FORMAT, 1, &pixelFormat);
glGetInternalFormativ(GL_TEXTURE_2D, GL_RGBA8, GL_TEXTURE_IMAGE_TYPE, 1, &pixelType);
Of course, this means that you will need to be able to modify your data generation method to generate data in the above format/type pair.
Once you've taken steps to appease the driver, your next possibilities are using buffer objects to store your pixel transfer data. This probably won't help overall performance, but it can reduce the CPU burden.
However, in order to take the best advantage of this, you need to be able to generate your pixel data "directly" into the buffer object's memory by mapping it. If you are able to do this, then you can probably get back some of the CPU cost of the upload. Otherwise, it may not be worthwhile.
If you do this, you should use proper buffer object streaming techniques.
Double-buffering your texture may also help. That is, while you're rendering from one texture object, you're uploading to another one. This will prevent GPU stalls that wait for the prior rendering to complete. How much this helps really depends on how you're rendering.
Without knowing more about the specific circumstances of your application, there's not much more that can be said.