#77030 - Chris Holmes - Mon Mar 27, 2006 4:26 pm
Quick 2 questions.
If you're working with a large number of textures, is there a way to unload textures from the unit, or does that get handled automatically in hardware? Also, is there a way to query the amount of available texture memory?
Thanks,
Chris
#77062 - Webez - Mon Mar 27, 2006 9:39 pm
You can use glResetTextures to unload all textures. Still no function to unload only one
To know how much memory is available you could have a counter that can be increased by the size of the texture that you load ( a 128x128 8 bit texture is 128x128x1 bytes) or you can try to use the variable nextBlock that libnds uses to point where it should put next texture.
Last edited by Webez on Tue Mar 28, 2006 8:01 am; edited 1 time in total
#77067 - Payk - Mon Mar 27, 2006 11:31 pm
hey i got same problem... i want to draw at textures. its ok and runs fine but if i try to update texture with that it doesnt make that update anymore.
if i use glResetTextures and draw again it runs a view times again. So i wanted to reset each time but while it resets all textures, the screen is black for a short moment. dont like that of course...any ideas?
#77069 - Chris Holmes - Mon Mar 27, 2006 11:33 pm
You shouldn't be "updating" textures at all. OpenGL wasn't designed
to work that way. Loading a texture is a relatively slow operation and
isn't something that you want to do every frame.
If there are some extra textures in memory, that's fine. Don't worry about that unless you start running out of texture memory. The better question is why are you editting textures on the fly? You can probably change what you're doing so that you don't need to edit textures on the fly.
Chris
#77081 - tepples - Tue Mar 28, 2006 2:16 am
Chris Holmes wrote: |
The better question is why are you editting textures on the fly? You can probably change what you're doing so that you don't need to edit textures on the fly. |
Put your mouse pointer on this window's scrollbar and drag the box up and down. Now do this while turning your head in random directions.
I want to draw a television set that displays a moving image. In the simplest case, the quad representing the screen needs to use a different texture for each frame of video. This video is generated on the fly, either from decompression of a compressed video bitstream (yay DPG) or algorithmically from what is going on elsewhere in the game world. And I may want to use more than one quad for the screen so that I can simulate the distortions of bad reception until the player drags the on-screen rabbit ear antenna into the proper position or until the player leaves the tunnel or until the player sobers up.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#77114 - Payk - Tue Mar 28, 2006 11:21 am
ok i want to chnage that on fly. The reason is that i need a 128x128 texture for the ground and want to draw flowers and shadows on it.on that way i gonna need just 2 polygons for entiry ground. other reason would be an animated water texture...ok the water could be animated by swapping its texture but for the ground i really need that! now it runs fine but just in that moment of refresh the screen gets black for a very short moment. but i gonna save the renderrimage to a bg-layer before refreshing texture so that black must be invisible...
#77115 - Payk - Tue Mar 28, 2006 11:22 am
and also i never said that i gonna refresh textures each frame...it just happens in some moments which isnt often...
#77123 - masscat - Tue Mar 28, 2006 1:35 pm
Yes you can edit textures on the fly. The tricky bit is finding where they are in the VRAM memory. You could keep track of this as you load textures (similar to tracking the amount of memory described above - you can see how libnds allocates texture memory by downloading its source).
Then to update the texture you lock the bank the texture is in, allowing the ARM access to the memory, write to the VRAM memory and then restore the bank to VRAM_?_TEXTURE. The next time you use the texture it will be updated.
Code: |
vramSetBankA(VRAM_A_LCD);
VRAM_A[100] = count++;
vramSetBankA(VRAM_A_TEXTURE); |
You must access the VRAM as 16 or 32 bit words as I do not believe VRAM is byte addressable.
EDIT:
For a short term solution you could use the following code which is a hack of the libnds glTextImage2D function to pass the address of the texture back. The bit in the extern "C" braces is declarations for private, i.e. not declared in the header file, function used in libnds. The extern "C" is needed if you are using the C++ compiler.
Code: |
extern "C" {
/* Out come some private GL functions */
uint32* getNextTextureSlot(int size);
void glTexParameter( uint8 sizeX, uint8 sizeY,
uint32* addr,
uint8 mode,
uint32 param);
}
//---------------------------------------------------------------------------------
// Similer to glTextImage2D from gl it takes a pointer to data
// Empty fields and target are unused but provided for code compatibility.
// type is simply the texture type (GL_RGB, GL_RGB8 ect...)
//---------------------------------------------------------------------------------
int glTexImage2D_retAddr( int target, int empty1, int type,
int sizeX, int sizeY,
int empty2, int param,
uint8* texture, uint32 **addr) {
//---------------------------------------------------------------------------------
uint32 size = 0;
// uint32* addr;
uint32 vramTemp;
size = 1 << (sizeX + sizeY + 6);
switch (type) {
case GL_RGB:
case GL_RGBA:
size = size << 1;
break;
case GL_RGB4:
size = size >> 2;
break;
case GL_RGB16:
size = size >> 1;
break;
default:
break;
}
*addr = getNextTextureSlot(size);
if(!*addr)
return 0;
// unlock texture memory
vramTemp = vramSetMainBanks(VRAM_A_LCD,VRAM_B_LCD,VRAM_C_LCD,VRAM_D_LCD);
if (type == GL_RGB) {
// We do GL_RGB as GL_RGBA, but we set each alpha bit to 1 during the copy
u16 * src = (u16*)texture;
u16 * dest = (u16*)(*addr);
glTexParameter(sizeX, sizeY, *addr, GL_RGBA, param);
while (size--) {
*dest++ = *src | (1 << 15);
src++;
}
} else {
// For everything else, we do a straight copy
glTexParameter(sizeX, sizeY, *addr, type, param);
swiCopy((uint32*)texture, *addr , size / 4 | COPY_MODE_WORD);
}
vramRestoreMainBanks(vramTemp);
return 1;
}
|
#77141 - Payk - Tue Mar 28, 2006 5:15 pm
dirty methods...but i like that idea i will sit down and code a bit... Thanx for giving me such a clear dirrection. Perhaps u saved my project...THANX UR GREAT
#77148 - Payk - Tue Mar 28, 2006 6:07 pm
just watched ur homepage Quote: |
DSLinux - if it has got a processor stick Linux on it. |
hehe funny... hey but another thing: That term u gave us just returns (0 || 1)...Ok should be solved easily... But if i know how many textures i will add (and their size,type and other things) would it be easy to say: First texture is mapped to 0x6000000 (i know its a bg address just an example). So if i add my textures in a specified order i could also know where my texture is... I mean they wont map textures to addresses by randomnumbers... So if i set up vrambank_a to a texturebank. Where would be the first texture i add? Could i then initialize an array to that adress and after binding texture just modify that array? (Like framebuffermode...)
#77151 - Payk - Tue Mar 28, 2006 6:28 pm
Did u watched "getNextTextureSlot(size);"? so that should be the adress i think... So it would be possible to return that addres intead of returning a bool value... But if i use that modified function to add textures,it will also need the rest of videoGl.h. Or more bad it would need the rest of ndslib/libnds... So that wouldnt be that easy to find out where the texture was putten in...Best would be VRAM_A_TEXTURE begins at 0x6.....
VRAM_A_TEXTURE is a #define i think. So if we know the correct address and unlock the vram we can map to texture dirrect. then we have to lock rambanks again...(I think that was that what u meaned...) Yes its an great idea... and that extern "c" means that this function is a modified version and has to be called instead..But that modified calls other functions(which perhaps arent accesable from outside of libnds) too.
Last edited by Payk on Tue Mar 28, 2006 6:31 pm; edited 1 time in total
#77152 - Webez - Tue Mar 28, 2006 6:31 pm
If you need the texture address get the one in nextBlock before allocating the texture.
#77153 - masscat - Tue Mar 28, 2006 6:31 pm
You use the function in the same way as glTexImage2D which returns 1 if successful or zero otherwise. What I added was the "uint32 **addr" parameter. It is through this parameter that the address is returned. For example:
Code: |
uint32 *my_texture_address;
/* setup your textures */
glTexImage2D_retAddr( 0, 0, GL_RGB4, TEXTURE_SIZE_128, TEXTURE_SIZE_128, 0, TEXGEN_TEXCOORD, texture_data, &my_texture_address);
/* do some other stuff */
/* change the texture in VRAM */
uint32 vram_temp = vramSetMainBanks( VRAM_A_LCD, VRAM_B_LCD, VRAM_C_LCD, VRAM_D_LCD);
for ( i = 0; i < texture_size; i++) {
my_texture_address[i] = new_data;
}
vramRestoreMainBanks( vram_temp);
|
Note that I am using vramSetMainBanks to lock all the VRAM banks.
You could work out which bank your texture has been stored in from the address and only lock and unlock that bank.
EDIT: Or as Webez said, just read nextBlock before you call glTexImage2D. All you need to do is declare the following in your source.
Code: |
extern uint32* nextBlock; |
The problem with all these methods is that they rely on the internal workings of libnds and this will change in the future and your code will break, hence the "short term fix" I said in my first post.
#77160 - Payk - Tue Mar 28, 2006 7:55 pm
thanx that all works for me...But it doesnt help me. while i update that textures, the models which have that texture dissapears untill next frame (very short moment but i hate that). And also the texture now has black parts (i got an idea why rgb and rgba..). So do the textures get black for short in ur projects too? or do i call that function at wrong time?
[Images not permitted - Click here to view it]
and do u like that?
Edit:I have to say that this short moment in that the screen gets black, is much shorter on hardware then my method before...so thanx!
#77162 - tepples - Tue Mar 28, 2006 8:02 pm
Have you tried double-buffering the texture that must be rewritten? Allocate two textures and modify the one that isn't being displayed.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#77165 - Payk - Tue Mar 28, 2006 8:14 pm
yes sure first i wanted to do that. But its seems like while VRAMBANKS are unlocked (to acces it) the textures cant be displayed. So best would be to make that timer interval between unlock and locking as small as possible... So i going to try dmacopy instead putting it pixel_by_pixel with a loop. But the problem is that dmacopy doesnt support changing each bit. That is neccesary if u look at my picture. That should make it better. And i watched that sources of libnds some minuts ago...
0x06800000<<Here the first texture will be. its the address. I have no clue for which ram bank but i think its for rambank_a (just a feeling that they dont begin with VRambank_b)
#77166 - Payk - Tue Mar 28, 2006 8:33 pm
ok did u saw my picture i posted? There are black lines all over the texture...i thought its the alphabit but it wasnt...i have no idea why. does anybody knows why?
#77167 - Payk - Tue Mar 28, 2006 9:23 pm
something new:
That black lines appaers because memory wants a 32 bit pixel. So i tried that Code: |
for(yy=0;yy<256;yy++){
for(xx=0;xx<256;xx++){
my_texture_address[xx+(yy*256)] = BodenImage[xx+(yy*256)] | (BodenImage[xx+(yy*256)] << 16);
}
}
|
And guess what? the black lines arent there anymore but the texture is still wrong. Now where all black lines were, a completly wrong pixel appeared which should be somewhere else in the texture...So u just need a loop which makes 2 16bit pixels become one 32bit-pixel-group. i am tired so i m not going to make that loop today... So thanx all u guys for helping me with that. I think i would never had found out what u told me. Thanx ur great devers.
#77172 - Webez - Tue Mar 28, 2006 9:35 pm
A pixel can't be 32 bit
#77174 - Payk - Tue Mar 28, 2006 9:56 pm
i know. i didnt meaned that one pixel has 32 bit. I meaned that u have to put 2 pixels in a 32bitWord. dont know how to explain u all see that i am bad at english...
But that should show u what i mean:
Code: |
my_texture_address[i]=BodenImage[i] | (BodenImage[i] << 16); |
So in that u32 we would see: 1010 0101 0110 0001
________________________^Pixel1___^Pixel2
Ok actually vice versa (u no Last Significant Bit is first bit we would read)
#77177 - masscat - Tue Mar 28, 2006 10:27 pm
You could access each pixel individually (assuming you are using GL_RGB or GL_RGBA format textures which has a 16bit pixel) by casting my_texture_address to a uint16 pointer:
Code: |
uint16 *pixel_pointer = (uint16 *)my_texture_address; |
What you cannot do is access each byte of VRAM individual as VRAM is not byte addressable (I am not sure if this is correct mind).
As for VRAM banks being locked for ARM access and the texture not being displayed then, yep, this is what happens. To cope with this you either will have to update your textures and release the VRAM bank before redrawing your screen or implement double buffering as tepples suggested.
For double buffering you could, for example, store a copy of the texture in VRAM A and another in VRAM B. This way you could lock VRAM A for ARM access whilst the graphics hardware is happily accessing the texture in VRAM B. Then switch over when you have updated the texture.
The problem with double buffering is that the texture management in libnds, today, does not make it easy to support as you cannot force a texture into a specific VRAM bank. Another limitation of libnds textures is the subject of this topic, i.e. you cannot free a single texture.
The good thing is that libnds will improve and/or somebody will come along and write some texture management code that can live along side it. I have been thinking about doing some sort of texture management as I want to implement a window system using the 3D hardware. Only initial thoughts at the moment whilst I learn more about the hardware.
#77180 - Payk - Tue Mar 28, 2006 11:40 pm
yeah ur like me...
my first thought when i read source of videogl.c was : "Can i change entiry system so its possible to move textures arround in memory or change the bank..." and i aslo thought about a window based system for 3D. But damn u know that we just have about 640 kb... So i would recommand to render a single window and map that to bg before rendering next one. On that way u could have as much wins as u need...
And that thing with that vrambank that u cant choose where the texture is located...I think shouldnt be that hard to solve. I found out that the rambank_a_texture starts at 0x06800000. and we know which size the banks have so i can calculate where the others are...Ok i really think a new managment must appear and i am going to work for that. as i see u gonna start soon, too. Better would be teamwork... Interessted? send me a pm... and i got some functions for a api ready to use.
#77241 - tepples - Wed Mar 29, 2006 6:53 pm
masscat wrote: |
As for VRAM banks being locked for ARM access and the texture not being displayed then, yep, this is what happens. To cope with this you either will have to update your textures and release the VRAM bank before redrawing your screen or implement double buffering as tepples suggested.
For double buffering you could, for example, store a copy of the texture in VRAM A and another in VRAM B. This way you could lock VRAM A for ARM access whilst the graphics hardware is happily accessing the texture in VRAM B. Then switch over when you have updated the texture. |
Either that or put them in the same bank and then copy them in during blanking time. That worked on the NES, Game Boy, and GBA; does it work on Nintendo DS as well?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#77268 - Payk - Wed Mar 29, 2006 9:06 pm
real? when exactly is that time? after swiWaitForVBlank or before?