eugene.chepurnykh's picture

Trouble with GetTexImage

I have one trouble. I've googled in the internet , but ... :(

        private static uint copyTexture(uint textureId, Size textureSize)
        {
            TextureTarget textureTarget = TextureTarget.Texture2D;
            // Prepare new texture.
            uint newTextureId;
            GL.GenTextures(1, out newTextureId);
            GL.BindTexture(textureTarget, newTextureId);
            GL.TexParameter(textureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
            GL.TexParameter(textureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
 
            // Bind old texture and get the texels.
            GL.BindTexture(textureTarget, textureId);
            GL.TexParameter(textureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
            GL.TexParameter(textureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
 
            //Texture.RGBA_BPP - 4 (BPP - bytes per pixel).
            byte[] texels = new byte[textureSize.Width * textureSize.Height * Texture.RGBA_BPP];
            GL.GetTexImage(textureTarget, 0, PixelFormat.Rgba, PixelType.UnsignedByte, texels);
 
            // Copy texels to new texture.    
            GL.BindTexture(textureTarget, newTextureId);
            GL.TexImage2D(textureTarget, 0, PixelInternalFormat.Rgba, textureSize.Width, textureSize.Height, 0,
                    PixelFormat.Rgba, PixelType.UnsignedByte, texels);
 
 
            // Detach textures.
            GL.BindTexture(textureTarget, 0);
 
            return newTextureId;
        }

Next GL command after TexImage2d caused to exception with "Wrong GL operation" description.

Does anybody make the same thing?

Of course I know about buffers, but the task is copy one texture to another.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Please place code inside <code></code> tags - it's much easier to read that way.

The TexImage2D documentation details which error condititions may arise (look at the bottom of the page). This method may cause InvalidEnum, InvalidValue or InvalidOperation errors if used incorrectly - are you getting one of those errors?

Does the error occur no matter what the next command is?

Finally, you should use CopyTexImage2D to copy one texture to another. This will be many times faster than reading back the texture to system memory and uploading it again to video memory.

eugene.chepurnykh's picture

I'm sorry for unconvience. I will try this in future... (about <code/> blocks).
As I said, I've got an error like ("Wrong GL operations") and nothing more...
Yes, the error occured regardless of type next command.
But I have one idea, I've looked in debugger and know that textureSize are not degree of 2.
May be in this I have a trouble.

Thank you for suggestion. I will try CopyTexImage2D for my purpose. Do you have any working sample?

the Fiddler's picture

If your card supports OpenGL 2.0+, it should automatically support non-power-of-two textures. Every video card sold after 2003 should support this (except for Intel IGPs). This could be the cause of the problem, indeed.

Edit: it seems that CopyTexImage can only copy the framebuffer to a texture and not a texture to a texture, so it can't do what you want it to (please correct me if I am mistaken).

eugene.chepurnykh's picture

There is another question. Is anybody knows -

byte[] texels = new byte[textureSize.Width * textureSize.Height * Texture.RGBA_BPP];

Am I right with determining size of buffer for new textures?

I've looked in the debugger on texels data - there are a good data (at least, it looks like a good data).

But the interesting thing - when I took place at

GL.TexImage2D(textureTarget, 0, PixelInternalFormat.Rgba, textureSize.Width, textureSize.Height, 0,
PixelFormat.Rgba, PixelType.UnsignedByte, <b>IntPtr.Zero</b>);

OpenGL falling down later...

the Fiddler's picture

There's not enough information to debug the issue:

  1. How are you detecting the error? Are you using the debug version of OpenTK or are you calling GL.GetError() manually?
  2. Can you paste the *exact* error message? "Wrong GL Operation" could mean anything, while "InvalidOperation" is a specific error that occurs under specific circumstances.
  3. Which is the exact method that generates the error?
  4. Which version of OpenTK are you using? (some versions have known issues)

Assuming Texture.RGBA_BPP equals 4, the texel array should be big enough to hold the texture data. However, getting this wrong wouldn't generate an OpenGL error: you'd either get an AccessViolationException or you'd get silent memory corruption.

The GL.TexImage2D call looks correct, assuming Width/Height are positive numbers, textureTarget is valid and the bound texture id is not 0.

eugene.chepurnykh's picture

To Fiddler: Thank you for feedback.
I've resolve my trouble. The problem was - I've tried operate with textures outside rendering contexts.
Another problem - source texture was ARB texture and I tried to make ARB texture. I don't know which options needing to set, but in my case all works fine for 2D texture only. My college says that it's possible to make TexSubImage2D calls not only for TextureTarget.Texture2D parameter but I can't to do that. In any cases I'm printing "working" code. May be it can be useful for somebody.

       public const TextureTarget TEXTURE_TARGET_TYPE = TextureTarget.Texture2D;
       public const int RGBA_BPP = 4;
 
       private static uint createTextureFrom(TextureTarget textureTargetSource, uint textureId, Size textureSize)
        {
            // Bind old texture and get the texels.
            GL.BindTexture(textureTargetSource, textureId);
 
            byte[] textureData = new byte[textureSize.Width * textureSize.Height * RGBA_BPP];
            GL.GetTexImage(textureTargetSource, 0, PixelFormat.Bgra, PixelType.UnsignedByte, textureData);
 
            // Prepare new texture.
            uint newTextureId;
            GL.GenTextures(1, out newTextureId);
            GL.BindTexture(TEXTURE_TARGET_TYPE, newTextureId);
            initTexture(MathHelper.NextPow2Size(new Size(textureSize.Width, textureSize.Height)), false);
 
            // Copy source texture to target.
            GL.TexSubImage2D(TEXTURE_TARGET_TYPE, 0, 0, 0, textureSize.Width, textureSize.Height,
                    PixelFormat.Bgra, PixelType.UnsignedByte, textureData);
 
            return newTextureId;
        }
 
       private static void initTexture(Size textureSize, bool isTiled)
        {
            GL.TexParameter(TEXTURE_TARGET_TYPE, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
            GL.TexParameter(TEXTURE_TARGET_TYPE, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
            if (isTiled)
            {
                GL.TexParameter(TEXTURE_TARGET_TYPE, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
                GL.TexParameter(TEXTURE_TARGET_TYPE, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
            }
 
            GL.TexImage2D(TEXTURE_TARGET_TYPE, 0, PixelInternalFormat.Rgba, textureSize.Width, textureSize.Height, 0,
                    PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
        }

MathHelper.NextPow2Size - it's simple function that searching nearest width and height that must be pow of two. The algorithm is trivial.

P.S. Using FBOs with copying of textures much simple and faster therefore if possible to use FBO - you must do it.