Artifacts with fullscreen/windowed

Started by Evil-Devil, May 17, 2006, 11:34:48

Previous topic - Next topic

Evil-Devil

When i switch from windowed to fullscreen without destroying the display I have artifacts on the switched display. Is it really needed to destroy the display first, set the display to fullscreen, create it new and reload ALL resources again?

I am just asking cause switching the displaymode does only require a reset of the matrixes. I hoped that might appear to fullscreen/windowed switching too.

Benny

Evil-Devil


Matzon

generally it's recommended to destroy and re-create/load all textures. Just switching displaymode - though it is supported - is somewhat unstable in some drivers.

Evil-Devil

Thx matzon.

Now I can revisited the design of my programm.

Sardtok

Agh, that's how I implemented my program first, then I found how to fix my ortho, and I changed it to change display without reloading textures and such...
Works fine on my card, but if it's not safe I guess I should go back to the old way...
Hmph... o.O
Oh well, it's not so bad, the texture reloading is fast, and I've even done some optimizing on the texture loading/reloading since I removed the display destruction...

Good to know though... ;)

Here's the code I use for reloading and such, I think it's pretty decent, but I could be wrong (As I only code once a year or so):

   /**
     * Loads a texture if it hasn't already been loaded, otherwise it returns that texture.
     *
     * @param fileName the name of the image file for the texture you are getting
     * @return the texture that was loaded, or found in the HashMap of already loaded textures. Returns null if the file could not be loaded.
     */
    public Texture getTexture(String fileName) {
        
        // Check if texture has already been loaded
        Texture tex = (Texture)textures.get(fileName);
        if(tex != null)
            return tex;
        
        int[] textureVars = loadTexture(fileName);
        
        if(textureVars == null || textureVars.length != 5)
            return null;
        
        // Create image (either resized by copying, else directly from IL)
        if (textureVars[1] != textureVars[3] || textureVars[2] != textureVars[4]) {
            tex = new Texture(textureVars[0], textureVars[1], textureVars[2], textureVars[3], textureVars[4]);
        } else {
            tex = new Texture(textureVars[0], textureVars[1], textureVars[2]);
        }
        textures.put(fileName, tex);
        
        // revert the gl state back to the default so that accidental texture binding doesn't occur
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        
        return tex;
    }
    
    /**
     * Loads the texture with the given fileName
     *
     * @return an int array with the following form: {glImageHandle, width, height, textureWidth, textureHeight}
     */
    public int[] loadTexture(String fileName) {
        
        int ilImageHandle;
        int glImageHandle;
        IntBuffer scratch = BufferUtils.createIntBuffer(1);
        
        // Create and bind image in DevIL
        IL.ilGenImages(scratch);
        IL.ilBindImage(scratch.get(0));
        ilImageHandle = scratch.get(0);
        
        // Load image
        try {
            if(!IL.ilLoadFromStream(getClass().getResourceAsStream(fileName),IL.IL_TYPE_UNKNOWN))
                return null;
        } catch(IOException e) {
            Sys.alert("Error", "Error while loading texture: " + fileName);
            return null;
        }
        
        // Convert image to RGBA
        IL.ilConvertImage(IL.IL_RGBA, IL.IL_BYTE);
        
        // Get image attributes
        int width = IL.ilGetInteger(IL.IL_IMAGE_WIDTH);
        int height = IL.ilGetInteger(IL.IL_IMAGE_HEIGHT);
        int textureWidth = getNextPowerOfTwo(width);
        int textureHeight = getNextPowerOfTwo(height);
        
        ByteBuffer imageData = null;
        // resize image according to poweroftwo
        if (textureWidth != width || textureHeight != height) {
            imageData = BufferUtils.createByteBuffer(textureWidth * textureHeight * 4);
            IL.ilCopyPixels(0, 0, 0, textureWidth, textureHeight, 1, IL.IL_RGBA, IL.IL_BYTE, imageData);
        } else {
            imageData = IL.ilGetData();
        }
        
        // create OpenGL counterpart
        GL11.glGenTextures(scratch);
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, scratch.get(0));
        glImageHandle = scratch.get(0);
        
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, textureWidth, textureHeight,
                          0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, imageData);
        
        // Delete image in DevIL
        scratch.put(0, ilImageHandle);
        IL.ilDeleteImages(scratch);
        
        return new int[]{ glImageHandle, width, height, textureWidth, textureHeight };
    }
    
    /**
     * Reloads the texture with the given filename
     *
     * @param fileName the name of the image file to reload
     */
    public void reloadTexture(String fileName) {
        Texture tex = (Texture)textures.get(fileName);
        if(tex == null)
            getTexture(fileName);
        else {
            int[] textureVars = loadTexture(fileName);
            tex.setTextureID(textureVars[0]);
            tex.setWidth(textureVars[1]);
            tex.setHeight(textureVars[2]);
            tex.setTextureWidth(textureVars[3]);
            tex.setTextureHeight(textureVars[4]);
            tex.calculateRatio();
        }
    }
    
    /**
     * Reloads all textures currently loaded.
     */
    public void reloadTextures() {
        Iterator reloadIterator = textures.keySet().iterator();
        while(reloadIterator.hasNext()) {
            String key = (String)reloadIterator.next();
            reloadTexture(key);
        }
    }


Well,
pretty close to the code in the wiki tutorial, but moved some stuff to the load function, while keeping the get function...
Requires an function call and such, but makes reloading a lot nicer than passing a bool to the getTexture method. ;)
Anyway, I'm pretty sure this should work well, but then again, I haven't tested it with lots and lots of textures...[/code]
igg -- Take me off for great justice?

darkprophet

If you store the Images (in buffers) of the texture somewhere, it should be pretty dam quick just to cycle through those again and upload them (will take a DMA transfer hit, but thats no problem)...

Your duplicating memory (one on the GPU memory and one on normal RAM), so be careful with that..

Evil-Devil

For reloading the textures on display fullscreen switching I prefer the full reload method. Cause you don't have to keep the texture data in the RAM.

And normally users switch the screen resolution in the options screen, before they start the game, so there isn't that much to reload.

Sardtok

QuoteYour duplicating memory (one on the GPU memory and one on normal RAM), so be careful with that..

Wouldn't I be duplicating memory only if I stored both the IL data and the GL data, like you're suggesting (or was it meant as a warning to the suggested approach)?
The way things are now I always delete the version stored in ordinary memory.
The DMA transfer hit would happen anyway wouldn't it, whether the textures stay in memory all along or if they are read from the drive to memory and then to video memory.
igg -- Take me off for great justice?

darkprophet

Keeping the textures in memory has the advantage of possibly not having to read the textures from the drive again with HD seeks and such. I found that to be the bottleneck when using TGA or DDS.

DP