Results 1 to 10 of 10

Thread: Opengl Texture Management

  1. #1

    Opengl Texture Management

    Hi everyone

    I've been looking a possible texture management solutions for my current project and thought I'd get some input from you all.

    The problem
    ---------------


    opengl only allows a limited number of resident texture objects (got by glGenTextures). But most games have a large number of textures that need to be used.

    The solution
    --------------

    write a management class that will use glCopyTexImage2D to update the textures.



    What I think would be usefull to many people is how to go about writting the management class.

    Personally the one I'm writting will allow the developer to pregenerate a number of blank texture objects of various sizes. Then as the game/app requires a texture it checks to see if it is already active and if not gets a texture object id from the management system and copys the pixel data to video memory.

    There are also a number of things to do with unloading images if they are no used very often.

    Anyone want to comment on how they solved this problem? I'm hoping to get varous poonts of view for people to look at. once my own code is written and working I'll post it on this thread for people to use.

    Dean
    <A HREF="http://www.myhpf.co.uk/banner.asp?friend=139328">
    <br /><IMG SRC="http://www.myhpf.co.uk/banners/60x468.gif" BORDER="0">
    <br /></A>

  2. #2

    Opengl Texture Management

    i personally think it would be much too slow. i believe opengl would be much faster to swap the textures itself..

    When you gen extra textures and video mem is filled it will generate in system mem and swap it to video texbuffer when it's needed. glcopyteximage2d takes alot of time

    but anyways.. i hate texture management write a class where i can set things like compresssion and which filtering mode to be used and make it able to load all the much used gfx formats from filename and tstreams, and i'll love you for the rest of my days

    Regards Jeppe
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  3. #3

    Opengl Texture Management

    You?¢_~re driver is likely to just swap textures into vram when they?¢_Tre needed. What you should do is implement a user defined texture detail setting and make sure that when it?¢_Ts set to minimum all downsized and compressed textures fit in you?¢_Tre minimum target vram.

  4. #4

    Opengl Texture Management

    My main reason for asking this question is that I hit a snag in my current projet where glGenTextures returns a 0 in for the texture id, which doesn't seem to be valid. It appears to do this after it has already loaded a number of textures (about 5-6). I couldn't see the problem so I begain looking into the glCopy option.

    My current texture class can load from file or tstream, it used SDL_Image and SDL_RWops to accomplish this. If you're interested I'll post the code for you to look at
    <A HREF="http://www.myhpf.co.uk/banner.asp?friend=139328">
    <br /><IMG SRC="http://www.myhpf.co.uk/banners/60x468.gif" BORDER="0">
    <br /></A>

  5. #5

    Opengl Texture Management

    well here is my class and manager , let me know what you think.

    [pascal]
    unit SDLGLTexture;

    interface

    uses SDL, SDL_Image, SDLUtils, gl,glu, Classes;

    type

    TSDLGLTextureSize = (ts64x64,ts128x64,ts128x128,ts256x128,ts256x256,ts 512x512,ts1024x1024,ts1024x512, ts1024x12;

    TSDLGLTexture = class;

    TSDLGLTexture = class
    private
    FHeight: UInt16;
    FWidth: UInt16;
    FSize: TSDLGLTextureSize;
    FSurface: PSDL_Surface;
    FTextureID: GLuint;
    protected
    function CreateBlankSurface: PSDL_Surface;
    function CreateSurfaceFromFile(Filename: string): PSDL_Surface;
    function CreateSurfaceFromStream(AStream: TStream): PSDL_Surface; virtual;
    procedure CreateTexture;
    procedure RefreshTexture;
    public
    constructor Create(ASize: TSDLGLTextureSize);
    constructor CreateFromFile(ASize: TSDLGLTextureSize; AFilename: String );
    constructor CreateFromStream(ASize: TSDLGLTextureSize; AStream: TStream);
    destructor Destroy; override;
    procedure Activate;
    procedure DeActivate;
    property Width: UInt16 read FWidth;
    property Height: UInt16 read FHeight;
    property Size: TSDLGLTextureSize read FSize;
    property TextureID: GLuint read FTextureID;
    property Surface: PSDL_Surface read FSurface;
    end;

    TTextureManager = class
    private
    FTextureList: TStringList;
    protected
    function GetTexture(Name: string): TSDLGLTexture;
    property TextureList: TStringList read FTextureList;
    public
    constructor Create;
    destructor Destroy; override;
    function AddTexture(AName: string; ASize: TSDLGLTextureSize = ts256x256): TSDLGLTexture;
    function AddTextureFromStream(AName: string; AStream: TStream; ASize: TSDLGLTextureSize = ts256x256): TSDLGLTexture;
    function AddBlankTexture(AName: string; ASize: TSDLGLTextureSize = ts256x256): TSDLGLTexture;
    procedure DeleteTexture(AName: string);
    property Textures[Name: string]: TSDLGLTexture read GetTexture;
    end;

    const TextureManager: TTextureManager = nil;

    implementation

    uses SysUtils, sdlstreams;

    { TSDLGLTexture }
    type

    TTextureDimensions = record
    Width, Height: Integer;
    end;

    const SizeLookup: array[TSDLGLTextureSize] of TTextureDimensions =
    ( (Width : 64; Height : 64),
    (Width : 128; Height : 64),
    (Width : 128; Height : 12,
    (Width : 256; Height : 12,
    (Width : 256; Height : 256),
    (Width : 512; Height : 512),
    (Width : 1024; Height: 1024),
    (Width : 1024; Height: 512),
    (Width : 1024; Height: 12
    );

    constructor TSDLGLTexture.Create(ASize: TSDLGLTextureSize);
    begin
    inherited Create;
    FSurface := nil;
    FSize := ASize;
    FTextureID := 0;
    FWidth := SizeLookup[ASize].Width;
    FHeight := SizeLookup[ASize].Height;
    FSurface := CreateBlankSurface;
    Assert(FSurface <> nil,'SDLGLTexture.Create : Failed to Create Surface');
    end;

    constructor TSDLGLTexture.CreateFromFile(ASize: TSDLGLTextureSize;
    AFilename: String);
    begin
    inherited Create;
    FSurface := nil;
    FSize := ASize;
    FTextureID := 0;
    FWidth := SizeLookup[ASize].Width;
    FHeight := SizeLookup[ASize].Height;
    FSurface := CreateSurfaceFromFile(AFilename);
    Assert(FSurface <> nil,'SDLGLTexture.CreateFromFile : Failed to Create Surface');
    end;

    function TSDLGLTexture.CreateBlankSurface: PSDL_Surface;
    begin
    Result := SDL_CreateRGBSurface(
    SDL_HWSURFACE or SDL_SRCALPHA or SDL_RLEACCEL,
    FWidth, FHeight,
    32,
    //{$IFDEF IA32} (* OpenGL RGBA masks *)
    // $000000FF,
    // $0000FF00,
    // $00FF0000,
    // $FF000000
    //{$ELSE}
    $0000FF00,
    $00FF0000,
    $FF000000,
    $000000FF
    //{$ENDIF}
    );
    end;

    destructor TSDLGLTexture.Destroy;
    begin
    if Surface <> nil then
    SDL_FreeSurface(Surface);
    inherited Destroy;
    end;

    function TSDLGLTexture.CreateSurfaceFromFile(Filename: string): PSDL_Surface;
    var fs:TFileStream;
    begin
    fs := TFileStream.Create(Filename, fmOpenRead);
    try
    Result := CreateSurfaceFromStream(fs);
    finally
    fs.Free;
    end;
    end;

    procedure TSDLGLTexture.Activate;
    begin
    //
    if TextureID = 0 then
    begin
    // Generate Texture.
    CreateTexture;
    end
    else
    begin
    glBindTexture(GL_TEXTURE_2D, TextureID);
    end;
    end;

    procedure TSDLGLTexture.DeActivate;
    begin
    //
    glBindTexture(GL_TEXTURE_2D, 0);
    end;

    procedure TSDLGLTexture.CreateTexture;
    var Format: Cardinal;
    begin
    glEnable(GL_TEXTURE_2D);
    glGenTextures(1, @FTextureID);
    glBindTexture(GL_TEXTURE_2D, FTextureID);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); {Texture blends with object background}
    // glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); {Texture does NOT blend with object background}

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); { only first two can be used }
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); { all of the above can be used }
    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    // gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, Surface.pixels);
    Format := GL_RGB;
    if Surface.format.BitsPerPixel = 32 then Format := GL_RGBA;

    glTexImage2D(GL_TEXTURE_2D, 0, Format, Width, Height, 0, Format, GL_UNSIGNED_BYTE, Surface.pixels);
    end;

    constructor TSDLGLTexture.CreateFromStream(ASize: TSDLGLTextureSize;
    AStream: TStream);
    var Target: TStream;
    TempImage: PSDL_Surface;
    begin
    inherited Create;
    FSurface := nil;
    FSize := ASize;
    FTextureID := 0;
    FWidth := SizeLookup[ASize].Width;
    FHeight := SizeLookup[ASize].Height;
    Target.Position := 0;
    FSurface := CreateSurfaceFromStream(AStream);
    Assert(FSurface <> nil,'SDLGLTexture.CreateFromStream : Failed to Create Surface');
    end;

    function TSDLGLTexture.CreateSurfaceFromStream(AStream: TStream): PSDL_Surface;
    var Rwops: PSDL_RWops;
    begin
    Rwops := SDLStreamSetup(AStream);
    try
    Result := IMG_Load_RW(Rwops, 0);
    if Result <> nil then SDL_FlipRectV(Result, nil);
    finally
    SDLStreamCloseRWops(Rwops);
    end;
    end;

    procedure TSDLGLTexture.RefreshTexture;
    var Format: Cardinal;
    begin
    Activate;
    Format := GL_RGB;
    if Surface.format.BitsPerPixel = 32 then Format := GL_RGBA;
    glTexSubImage2D(GL_TEXTURE_2D, 0,0,0, Width, Height, Format, GL_UNSIGNED_BYTE, Surface.pixels)
    end;

    { TTextureManager }

    function TTextureManager.AddBlankTexture(AName: string;
    ASize: TSDLGLTextureSize): TSDLGLTexture;
    begin
    Result := TSDLGLTexture.Create(ASize);
    if Result <> nil then
    begin
    TextureList.AddObject(ExtractFileName(AName), Result);
    end;
    end;

    function TTextureManager.AddTexture(AName: string; ASize: TSDLGLTextureSize = ts256x256): TSDLGLTexture;
    begin
    Result := nil;
    if AName = EmptyStr then Exit;
    Result := Textures[ExtractFileName(AName)];
    if Result <> nil then Exit;
    if not FileExists(AName) then Exit;
    Result := TSDLGLTexture.CreateFromFile(ASize,AName);
    if Result <> nil then
    begin
    TextureList.AddObject(UpperCase(ExtractFileName(AN ame)), Result);
    end;
    end;

    function TTextureManager.AddTextureFromStream(AName: string; AStream: TStream;
    ASize: TSDLGLTextureSize): TSDLGLTexture;
    begin
    Result := nil;
    if AName = EmptyStr then Exit;
    Result := Textures[UpperCase(AName)];
    if Result <> nil then Exit;
    Result := TSDLGLTexture.CreateFromStream(ASize,AStream);
    if Result <> nil then
    begin
    TextureList.AddObject(UpperCase(AName), Result);
    end;
    end;

    constructor TTextureManager.Create;
    begin
    inherited Create;
    FTextureList := TStringList.Create;
    end;

    procedure TTextureManager.DeleteTexture(AName: string);
    var idx: Integer;
    begin
    idx := TextureList.IndexOf(AName);
    if idx <> -1 then
    begin
    TextureList.Objects[idx].Free;
    TextureList.delete(idx);
    end;
    end;

    destructor TTextureManager.Destroy;
    var i: Integer;
    begin
    for i := 0 to TextureList.Count-1 do
    begin
    TextureList.Objects[i].Free;
    end;
    TextureList.Free;
    inherited Destroy;
    end;

    function TTextureManager.GetTexture(Name: string): TSDLGLTexture;
    var idx: Integer;
    begin
    Result := nil;
    idx := TextureList.IndexOf(Name);
    if idx <> -1 then
    begin
    Result := TSDLGLTexture(TextureList.Objects[idx]);
    end;
    end;

    initialization

    TextureManager := TTextureManager.Create;

    finalization

    TextureManager.Free;

    end.
    [/pascal]
    <A HREF="http://www.myhpf.co.uk/banner.asp?friend=139328">
    <br /><IMG SRC="http://www.myhpf.co.uk/banners/60x468.gif" BORDER="0">
    <br /></A>

  6. #6

    Opengl Texture Management

    For anyone who is interested I found out what the problem with glGenTextures was, I was callign it from a separate thread within the application, it doesn't appear to like that, so I moved the call to the main thread and it all worked fine
    <A HREF="http://www.myhpf.co.uk/banner.asp?friend=139328">
    <br /><IMG SRC="http://www.myhpf.co.uk/banners/60x468.gif" BORDER="0">
    <br /></A>

  7. #7

    Opengl Texture Management

    Ahh. Multi-threading joy.

    A tip for those people lucky enough to be using an AMD 64-bit X2 dual-core processor and use the high-frequency performance counter for game timing. Place a call to SetThreadAffinity() near the start of your game code to make sure the main thread always runs on the same CPU. The values returned by QueryPerformanceCounter() can differ depending on which CPU the thread is running on when it calls QueryPerformanceCounter(). This can make the game timing jump all over the place, even backwards. If the thread affinity is set to 1, then the thread always runs on the one CPU and the results returned by QueryPerformanceCounter() are what you would normally expect.

  8. #8

    Opengl Texture Management

    Hmm,... I always thought that QPC is processor independant (and should correctly handle SpeedStep like CPU frequency jums).

    But now looked at MSDN docs and they have remarks for it:
    On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function.
    PS. Congratulations Sly for gettting "Word Lord" status!
    There are only 10 types of people in this world; those who understand binary and those who don't.

  9. #9

    Opengl Texture Management

    Even Serious Sam 2 has serious problems because of this discrepancy between QPC values on multi-CPU machines. I have to use a small utility called RunFirst that runs the demo using a process affinity of 1 to get it playing smooth.

    My wordy lordy yes I am a Word Lord.

  10. #10

    Opengl Texture Management

    I'm not sure if this is relevant... - http://www.openscenegraph.org
    <br /><br />There are a lot of people who are dead while they are still alive. I want to be alive until the day I die.<br />-= Paulo Coelho =-

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •