Sign in to follow this  
lar0922

Rendering sprites off screen

Recommended Posts

lar0922    122
Hi guys! Is it possible to draw ID3DXSprite sprites to something other than a D3D device, for example to a texture or something like that? Right now I'm writing an application which uses quite a lot of sprites, and rendering them all individually each frame eats up quite a lot of CPU power. What I would like to do is only render them all individually when a change in position/scale/etc has been made, and render one big texture (with all the smaller sprites on it) the rest of the time, so that no unnecessary calculations/transformations has to be made when not needed. Any advice would be much appreciated! Edit: Forgot to mention, this question is C++ related.

Share this post


Link to post
Share on other sites
MJP    19786
I don't believe that ID3DXSprite touches the render-target of the device at all, so I *think* it will render to whatever you have set as the current render-target. You could check for sure by running your program through PIX, and seeing whether IDirect3DDevice9::SetRenderTarget gets called by ID3DXSprite::Begin or ID3DXSprite::End. If it does mess with the render-target, you could always tell ID3DXSprite that you want to manage render-states yourself by specifying D3DXSPRITE_DONOTMODIFY_RENDERSTATE when you call ID3DXSprite::Begin. Of course if you do that you'll need to set all of the rener-states yourself, for things like alpha-blending, texture stage states, and texture filtering.

Share this post


Link to post
Share on other sites
Adam_42    3629
How many sprites are you drawing per frame?

Are you avoiding drawing sprites that are off the edges of the screen?

How many calls to ID3DXSprite::Begin() per frame? You should only need one.

Share this post


Link to post
Share on other sites
lar0922    122
Thanks a lot for your reply, MJP! I will look into that.

Adam_42: Thanks for the reply! As of right now I'm drawing 114 sprites per frame.
None of the sprites are off the edges of the screen.
Also, I'm only calling Begin() and End() once each frame, with multiple Draw() calls in between.
I'm having very little CPU usage when running the application on the computer I'm on right now, but while testing it on other systems with lower hardware specs I found that CPU usage was around 30% which is way too high as this is an application that is meant to be running in the background so keeping CPU usage down is a priority. I think it would help performance a lot to draw all the sprites as one, especially as there are no animations and the sprites are stationary in position most (almost all) of the time.

Share this post


Link to post
Share on other sites
Cantos    212
Yep, it's super easy.

I'm working on a project now that uses ID3DXSprite to render to a ID3DXRenderToSurface. You dont need to SetRenderTarget, you just go
// You cannot call BeginScene here if you are already in
// a IDirect3DDevice9::BeginScene() / EndScene() block
ID3DXRenderToSurface::BeginScene()
ID3DXSprite::Begin()

// draw your sprites

ID3DXSprite::End()
ID3DXRenderToSurface::EndScene()

Share this post


Link to post
Share on other sites
lar0922    122
Thanks for the replies!

I tried your method, Cantos, but I'm having problems trying to figure out how to draw the surface to the screen.

Share this post


Link to post
Share on other sites
Cantos    212
I worked this method out from the offscreen rendering sample here.

render_target.h
#pragma once

#include <d3d9.h>
#include <d3dx9.h>

#include "slr_types.h"

namespace slr
{
class render_target
{
friend class Sunshine;
friend class render_target_pool;
public:
render_target();
~render_target();

protected:
render_target(IDirect3DDevice9* D3DDevice, sint Width, sint Height);

inline IDirect3DTexture9* get_texture() const { return dynamic_texture; }
inline ID3DXRenderToSurface* get_render_surface() const { return render_surface; }
inline IDirect3DSurface9* get_texture_surface() const { return texture_surface; }

private:
IDirect3DTexture9* dynamic_texture;
IDirect3DSurface9* texture_surface;
ID3DXRenderToSurface* render_surface;
};
}



render_target.cpp
#include "render_target.h"

slr::render_target::render_target(IDirect3DDevice9* device,
sint width, sint height)
: dynamic_texture(NULL),
texture_surface(NULL),
render_surface(NULL)

{
HRESULT hr = D3DXCreateTexture( device,
width,
height,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&dynamic_texture );
if (FAILED(hr))
{
// error
}

D3DSURFACE_DESC desc;
hr = dynamic_texture->GetSurfaceLevel( 0, &texture_surface );
if (FAILED(hr)) // error

hr = texture_surface->GetDesc( &desc );
if (FAILED(hr)) // error

hr = D3DXCreateRenderToSurface( device,
desc.Width,
desc.Height,
desc.Format,
FALSE,
D3DFMT_D16,
&render_surface );
if (FAILED(hr))
{
// error
}

// clear the surface
render_surface->BeginScene(texture_surface,NULL);

device->Clear(0,NULL,D3DCLEAR_TARGET,0x0,1.0f,0);

render_surface->EndScene(0);
}



From there, you call get_texture() and use it in a normal call to ID3DXSprite::Draw(), or get_texture_surface() and use the surface in a IDirect3DDevice9::StretchRect onto the backbuffer.

Quote:
Just to clarify...all ID3DXRenderToSurface does is call IDirect3DDevice9::SetRenderTarget as well as keep the render-target texture and surface contained in one interface.
I did not know that. You seem to be indicating that you can pull a texture from the ID3DXRenderToSurface interface, is some of my above code redundant?

Share this post


Link to post
Share on other sites
MJP    19786
Quote:
Original post by Cantos
I did not know that. You seem to be indicating that you can pull a texture from the ID3DXRenderToSurface interface, is some of my above code redundant?


No you can't pull a texture from it, I must have been thinking of something else. But it does call SetRenderTarget for you, either with the surface you've provided or with a surface created internally (if the surface you provide isn't a valid render-target). So it look like what you're doing is perfectly fine.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this