An idea for saving VRAM with textures

Miscellaneous Forums/General Discussion/An idea for saving VRAM with textures

Ok, whilst i was trying to find ways round the lack of texture compression in blitz, i came up with an idea. Scarey, i know ;o)

NOW, you assign all your models textures. But have a limit on how many textures your going to use, for VRAM sake. Now, load in the other textures as images, or load and convert from a file, or store as data statement. That part doesn't matter too much, just as long as they end up in system RAM, which people have plently of. They would end up in arrays or banks. Now...

This requires a bit of management. When leaving an area, open up the texture buffers, and write over the textures, using the stored data. This can be done in stages, so as not to cause any slowdown. So, you never load or free anymore textures, just simply overwrite them, and you have as many textures as you want system RAM to hold.

I do understand this requires some management in code, but i think it's achievable. Anyone got anything to add or improve upon this idea?

The reason i'm posting this, is i have a big world to load into blitz, and it will use a fair number of textures.

i thought you could load textures, apply them and then FreeTexture them? or does that not free them from vram?

It does, but loading a texture take longer than construsting one. If you load a texture, everything will freeze until it's finished.

you're saying load all the textures with loadimage, then load them up in VRAM when needed and vice versa if not?

Interesting idea - could help overcome the surface count issue too.

Some of us have only 4 times as much RAM as VRAM tho. It's still significant. Sounds like a multi-threading idea to me but i dont see how you write over the texture without causing a temporary freeze? Dont have experience with that.

I'd copyrect or read/writepixelfast 'x' pixels per frame (have to test what didn't cause noticable slowdown). The tough part would be to ensure that this process began soon enough before you can actually see the texture on screen - its a 'zones' type conundrum.

The implications of the choking of the render pipeline here are huge, copying from RAM to VRAM is soooo slow and will impact the overall performance of the card. Texture switching in VRAM is expensive, switching with RAM is a killer.

I'd suggest a couple of things 1) Go buy a 256MB card for $50 (that's cheaper than 1 hour spent coding) or 2) make smaller textures and compact them all into 1 larger texture.

Doesn't Blitz already do this automatically?

John, that is something i thought about. I'm not sure if it's constantly swopping them though.

About choking the pipeline. For me personally, there will be zones where not alot is happening, and i might only be copying say 32x32 areas per frame, locking the buffer of the texture and reading from an array. Since people are using bloom filters and real time reflections, and what not, that require two renders and a copyrect, then i don't see it being particulary slow.

I will test this and post some code and get people to test. Thanks for the input so far :o)

Blitz does already do this already, but it doesn't mean that you couldn't make it more efficient. Blitz will do it at inconvenient times, and perhaps a lot of textures at once, whereas an intelligent system optimized for your game might be able to predict and spread the transfers out.

I'm still concerned that doing it manually might be slower from a technical standpoint, but only testing will tell you that. If you write a little test to see whether you can manually swap textures at the same sort of rate as Blitz does them automagically, then an intelligent, predictive texture management system could well be worth pursuing.

Well, i've done a few tests, and it seems like the biggest sped loss occurs when locking a texture for fast writing. On first look that is. Even writing one pixel to a texture without locking it, brings the speed right down. It seems the best way would be to up the transfer to say chunks of 10,000 pixels at a time.

The force to VRAM flag makes little if any difference.

Oh, and, is it just textures that get swapped in and out of video memory, or is it meshes as well?

Here is some code to demonstrate this. It could be further inproved by writting every other frame. But the way i see it, the quickier it's over with, the better :o) You can change the texture size plus the number of texels writte to the texture per frame:

Graphics3D 800,600
SetBuffer BackBuffer()

Global camera = CreateCamera()

Global tex_width = 512
Global tex_height = 512

Global texels_per_frame = 10000


Dim texture_array(tex_width-1,tex_height-1)

Global texture = CreateTexture(tex_width,tex_height,256)
SetBuffer TextureBuffer(texture)
	Color 255,0,0
	Rect 0,0,tex_width,tex_height

;copy this to the array
LockBuffer TextureBuffer(texture)
For x = 0 To tex_width-1
	For y = 0 To tex_height-1
		temp = ReadPixelFast(x,y,TextureBuffer(texture) )
		texture_array(x,y) = temp
	Next
Next

UnlockBuffer TextureBuffer(texture)

SetBuffer TextureBuffer(texture)
	Color 0,255,0
	Rect 0,0,tex_width,tex_height

SetBuffer BackBuffer()


Global x_pos = 0
Global y_pos = 0

Global frame
Global fps
Global timer
Global change = 0

Global sprite = CreateSprite()
EntityTexture sprite,texture
PositionEntity sprite,0,0,10

Global cube = CreateCube()
PositionEntity cube,2,0,10

While Not KeyHit(1)

	TurnEntity cube,1,1,1
	
	If KeyHit(200) Then
		change = 1
	End If


	If MilliSecs()<timer+1000 Then
								frame=frame+1
	Else
								fps=frame
								frame=0
								timer=MilliSecs()
	End If
	If change = 1 Then
		update_texture()
	End If
	UpdateWorld
	RenderWorld
	Text 10,10,"fps="+fps
	If change = 1 Then
		Text 10,30,"changing..."
		Text 10,40," x_pos = "+x_pos
	End If
	Flip 0
Wend
End


Function update_texture()

	temp = 0
	;SetBuffer TextureBuffer(texture)
	LockBuffer TextureBuffer(texture)
	Repeat
		WritePixelFast(x_pos,y_pos,texture_array(x_pos,y_pos),TextureBuffer(texture))
		x_pos = x_pos + 1
		If x_pos > (tex_width-1) Then
			x_pos = 0
			y_pos = y_pos + 1
			If y_pos > (tex_height-1) Then
				y_pos = 0
				change = 0
			End If
		End If
		temp = temp + 1
	Until temp > texels_per_frame
	
	UnlockBuffer TextureBuffer(texture)
	;SetBuffer BackBuffer()
	
End Function


If you run the above in fullscreen, i get a delay of less than a second with my computer and that's a 512x512 texture being transfered.

If you run the above in fullscreen, i get a delay of less than a second with my computer and that's a 512x512 texture being transfered.

A delay of just less than a second is a significant delay :)

Tbh, in the kind of game, i don't see it being a bit deal, if the computer slows down (i didn't mean to say delay, sorry), for less than a second whilst a texture transfers. I will look into further spacing out the transfers though. I can't think right now, of any quick way to test out the slow down blitz has...

Hmm, further testing has revealed that, textures only get put into VRAM when they are needed. Creating 20 1024x1024 texture cause no use of VRAM. But, if i texture a sprite with these, the textures get pulled into VRAM at that point.

Well, i've concluded the fastest way of doing is, is probably to create all the textures and store them in an array. Keep a managed system, where by when you enter a new area, texture all the entities in the scene. This will flush the textures used for the previous area, out of VRAM, as the new ones get copied across.