How to do hardware accelerated alpha blending in SDL? - c++

I'm trying to find the most efficient way to alpha blend in SDL. I don't feel like going back and rewriting rendering code to use OpenGL instead (which I've read is much more efficient with alpha blending), so I'm trying to figure out how I can get the most juice out of SDL's alpha blending.
I've read that I could benefit from using hardware surfaces, but this means I'd have to run the game in fullscreen. Can anyone comment on this? Or anything else regarding alpha transparency in SDL?

I have once playing with sdl hardware surfaces ant it wasn't the most pleasant experience. SDL is really easy to use, but when it gets to efficiency you should really stick with something that was especially designed for such task. OpenGL is a good choice here. You can always mix SDL (window and event management) with openGL (graphics) and use some of the already written code.
You can find some info on hardware surfaces here and here

Decided to just not use alpha blending for that part. Pixel blending is too much for software surfaces, and OpenGL is needed when you want the power of your hardware.

Use OpenGL with SDL. It's good to get to know the GL library (I hardly see a use for non-graphics accelerated stuff these days, even GUIs use it now). SDL_image has a way to check for alpha channel. My function that creates textures from a path to an image file (uses SDL_image's IMG_Load() function) has this:
// if we successfully open a file
// do some gl stuff then
SDL_PixelFormat *format = surface->format;
int width, height;
width = pow2(surface->w);
height = pow2(surface->h);
SDL_LockSurface(surface); // Call this whenever reading pixels from a surface
/* Check for alpha channel */
if (format->Amask)
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
else
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
SDL_UnlockSurface(surface);
pow2() just rounds the number to the next closest power of 2. A lot of video cards nowadays can handle non-power of 2 values for texture sizes but as far as I can tell, they are definitely NOT optimised for it (tested framerates). Other video cards will just refuse to render, your app may crash, etc etc.
Code is here: http://www.tatsh.net/2010-06-19/using-sdlimage-and-sdlttf-opengl

Related

glDrawPixels vs textures to draw a 2d buffer in OpenGL

I have a 2d graphic library that I want to use in OpenGL, to be able to mix 2d and 3d graphic. The simplest way seems to be with glDrawPixels, but many recent tutorial, and forums, suggest to use a texture with the command glTexSubImage2D, and then to draw a square with such a texture.
My question is: why? where is the advantage? It just adds one more step (memory buffer->texture->video buffer, instead of memory buffer->video buffer).
There are two main reasons:
glDrawPixels() is deprecated, and not available in the OpenGL core profile, or in OpenGL ES.
When drawing the image multiple times, a lot of repeated work can be saved by storing the image data in a texture.
It's quite rare that you would have to draw an image only once. Much more commonly, you'll draw it repeatedly, on each redraw. With glDrawPixels() you have to pass the image data into OpenGL each time. If you store it in a texture, you can draw it repeatedly, and OpenGL can reuse the same data each time.
To draw the content of a texture, you don't necessarily have to set up a shader, draw a quad, etc. You can use glBlitFramebuffer() to copy the texture content to the display.
Since OpenGL use a video memory, use a simple "draw pixel" must be really slow because you will do a lot GPU/CPU synchronisation for each draw.
When you use glTexSubImage2D, you ensure that your image will reside(all the time) into the video memory which is fast.
One way to load a texture inside video memory could be :
glCreateTextures(GL_TEXTURE_2D, 1, &texture->mId);
glTextureParameteri(mId, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(mId, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLsizei numMipmaps = ((GLsizei)log2(std::max(surface->w, surface->h)) + 1);
glTextureStorage2D(*texture, numMipmaps, internalFormat, surface->w, surface->h);
glTextureSubImage2D(*texture, 0, 0, 0, surface->w, surface->h,
format, GL_UNSIGNED_BYTE, surface->pixels);
glGenerateTextureMipmap(*texture);
Don't forget binding if you do not want to use direct state access.
However, if you still want to perform pixel draw (for example for procedural rendering), you must write your own fragment shader to be as fast as possible

Most Efficient Way to Retrieve Texture Pixel Data?

I know Directx for Dx9 at least, has a texture object where you are able to get only a small portion of the texture to CPU accessible memory. It was a function called "LockRect" I believe. OpenGL has glGetTexImage() but it grabs the entire image and if the format isn't the same as the texture's then it is going to have to convert the entire texture into the new pixel format on top of transferring the entire texture. This function is also not in OpenGL ES. Framebuffers is another option but where I could potentially bind a framebuffer where a color attachment in connected to a texture. Then there is glReadPixels which reads from the framebuffer, so it should be reading from the texture. glReadPixels has limited pixel format options so a conversion is going to have to happen, but I can read the pixels I need (which is only 1 pixel). I haven't used this method but it seems like it is possible. If anyone can confirm the framebuffer method, that it is a working alternative. Then this method would also work for OpenGL ES 2+.
Are there any other methods? How efficient is the framebuffer method (if it works), does it end up having to convert the entire texture to the desired format before it reads the pixels or is it entirely implementation defined?
Edit: #Nicol_Bolas Please stop removing OpenGL from tags and adding OpenGL-ES, OpenGL-ES isn't applicable, OpenGL is. This is for OpenGL specifically but I would like it to be Open ES 2+ compatible if possible, though it doesn't have to be. If a OpenGL only solution is available then it is a consideration I will make if it is worth the trade off. Thank you.
Please note, I do not have that much experience with ES in particular, so there might be better ways to do this specifically in that context. The general gist applies in either plain OpenGL or ES, though.
First off, the most important performance consideration should be when you are doing the reading. If you request data from the video card while you are rendering, your program (the CPU end) will have to halt until the video card returns the data, which will slow rendering due to your inability to issue further render commands. As a general rule, you should always upload, render, download - do not mix any of these processes, it will impact speed immensely, and how much so can be very driver/hardware/OS dependent.
I suggest using glReadPixels( ) at the end of your render cycle. I suspect the limitations on formats for that function are connected to limitations on framebuffer formats; besides, you really should be using 8 bit unsigned or floating point, both of which are supported. If you have some fringe case not allowing any of those supported formats, you should explain what that is, as there may be a way to handle it specifically.
If you need the contents of the framebuffer at a specific point in rendering (rather than the end), create a second texture + framebuffer (again with the same format) to be an effective "backbuffer" and then copy from the target framebuffer to that texture. This occurs on the video card, so it does not impose the bus latency directly reading does. Here is something I wrote that does this operation:
glActiveTexture( GL_TEXTURE0 + unit );
glBindTexture( GL_TEXTURE_2D, backbufferTextureHandle );
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glCopyTexSubImage2D(
GL_TEXTURE_2D,
0, // level
0, 0, // offset
0, 0, // x, y
screenX, screenY );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, framebufferHandle );
Then when you want the data, bind the backbuffer to GL_READ_FRAMEBUFFER and use glReadPixels( ) on it.
Finally, you should keep in mind that a download of data will still halt the CPU end. If you download before displaying the framebuffer, you will put off displaying the image until after you can again execute commands, which might result in visible latency. As such, I suggest still using a non-default framebuffer even if you only care about the final buffer state, and ending your render cycle to the effect of:
(1.) Blit to the default framebuffer:
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); // Default framebuffer
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glBlitFramebuffer(
0, 0, screenX, screenY,
0, 0, screenX, screenY,
GL_COLOR_BUFFER_BIT,
GL_NEAREST );
(2.) Call whatever your swap buffers command may be in your given situation.
(3.) Your download call from the framebuffer (be it glReadPixels( ) or something else).
As for the speed impact of the blit/texcopy operations, it's quite good on most modern hardware and I have not found it to have a noticeable impact even done 10+ times a frame, but if you are dealing with antiquated hardware, it might be worth a second thought.

Opengl float buffer

I'm writing my first ray tracer. I want to make it work in real-time.
I want to use opengl for display.
I want to write my screen to floating point buffer and display the buffer.
What extension and/or buffer type I need?
Thanks in advance!
I'm writing my first ray tracer. I want to make it work in real-time.
Ambitious!
I want to use opengl for display. I want to write my screen to floating point buffer and display the buffer.
OpenGL can read from float buffers directly, e.g.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, data);
But OpenGL may choose any internal format that matches your selection. GL_RGB internal format can be anything that can somehow store RGB data. You can be specific about what you want. For example GL_RGB16 tells OpenGL you want 16 bits resolution per channel. The implementation may choose to use 24 bits per channel, as this allows for 16 bit to be stored. But ultimately the implementation decides, which internal format it will be, based on the constraints you put upon it.
Floating point framebuffers and textures are supported in OpenGL through extensions GL_ARB_texture_float, GLX_ARB_fbconfig_float, WGL_ARB_fbconfig_float, but due to patent issues not all OpenGL implementations implement it (ATI and NVidia do).

low resolution in OpenGL to mimic older games

I'm interested in know how is the right way to mimic the low resolution of the older games (like Atari 2600) in OpenGL to do a fps game. I imagine the best way to do it is writing the buffer into a texture, put onto a quad and display it to the screen resolution.
Take a look of http://www.youtube.com/watch?v=_ELRv06sa-c, for example (great game!)
Any advice, help or sample-code will be welcome.
I think the best way to do it would be like you said, render everything into a low-res texture (best done using FBOs) and then just display the texture by drawing a sceen-sized quad (of course using GL_NEAREST as magnification filter for the texture). Maybe you can also use glBlitFramebuffer for copying directly from the low-res FBO into the high-res framebuffer, although I don't know if you can copy directly into the default framebuffer (the displayed one) this way.
EDIT: After looking up the specification for framebuffer_blit it seems you can just copy from the low-res FBO into the high-res default framebuffer using glBlitFramebuffer(EXT/ARB). This might be faster than using a texture mapped quad as it completely bypasses the vertex-fragment-pipeline (although this would have been a simple one). And another advantage is that you also get the low-res depth and stencil buffers if needed and can this way render high-res content on top of the low-res background which might be an interesting effect. So it would happen somehow like this:
generate FBO with low-res renderbuffers for color and depth (and stencil)
...
glBindFramebuffer(GL_FRAMEBUFFER, lowFBO);
render_scene();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 640, 480, 0, 0, 1024, 768,
GL_COLOR_BUFFER_BIT [| GL_DEPTH_BUFFER_BIT], GL_NEAREST);

Using libpng to "split" an image into segments

I'm trying to use libpng to split an image into different chunks. The reason being I can't load a texture larger than 512x512 on the hardware I'm working on currently. I accomplished this before with a mixture of SDL and SDL_Image. I basically used the srcrect argument in SDL_BlitSurface to copy just a portion of the image which I then converted into a OpenGL texture. Combine that with a simple loop horizontally then vertically I was able to get an array of textures each a max of 512x512. Then it was just a matter of rendering them at the correct position.
Right now, I don't have the luxury of using SDL, so I figured it's possible to just does this directly myself via libpng. Based on some googling I think its just a matter of using png_read_rows to read just which parts I need. But that's where I'm stuck, I'm not exactly sure how to do that.
Also, if you wonder why I don't just split the images in gimp/photoshop/paint or whatever, it's because I don't control them and am downloading them at runtime.
Thanks for the help in advance.
You don't have to mess with extracting the tiles. You can tell OpenGL to just use some portion of the data you give it to initialize the texture. Keyword is glPixelStorei(GL_UNPACK...) parameters. Say your input image has dimensions img.width and img.height and there are 4 bytes to a RGB pixel, i.e. one byte padding for each pixel and your subpicture is defined by subimg.off_x, subimg.off_y, subimg.width, subimg.height. Then you can load it like this:
glPixelStorei(GL_UNPACK_ROW_LENGTH, img.width)
glPixelStorei(GL_UNPACK_SKIP_PIXELS, subimg.off_x)
glPixelStorei(GL_UNPACK_SKIP_ROWS, subimg.off_y)
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
glTexImage2D(GL_TEXTURE_2D, GL_RGB, 0,
subimg.width, subimg.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixeldata)