#include "DarkSDK.h"
#include "d3d9.h"
#define D3D_FVF_2D_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
struct TransformedVertex // D3D_FVF_2D_VERTEX
{
float x, y, z, w; // Position of vertex in 3D space
DWORD color; // Color of vertex
};
IDirect3DDevice9* g_pd3dDevice = NULL;
void InitD3DFunc() {
g_pd3dDevice = dbGetDirect3DDevice();
}
void d3d_dot (int x1,int y1, int r, int g, int b, int a) {
TransformedVertex *pVertices = NULL;
TransformedVertex g_lineList[] =
{
{-1.0f, 0.0f, 0.0f, 1.0f, D3DCOLOR_ARGB( 255, 255, 0, 255 ) }, // Line #1
};
g_lineList[0].x=(float)x1;
g_lineList[0].y=(float)y1;
g_lineList[0].z=1.0f;
g_lineList[0].color=D3DCOLOR_ARGB ( a, r, g, b );
g_pd3dDevice->SetTexture(0,NULL);
g_pd3dDevice->SetTexture(1,NULL);
g_pd3dDevice->SetVertexShader(NULL);
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
g_pd3dDevice->SetFVF( D3D_FVF_2D_VERTEX );
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
g_pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST,1,g_lineList,sizeof(TransformedVertex));
}
The problem is, it's way too slow. The framerate decreases to 40 FPS(from 60 FPS) when I draw just 100x100 pixels every frame, with zero extra calculations. Could anyone suggest a quicker function?
Fastest possible single pixel drawing?
I'm trying to make a sand game, such as PyroSand, with the Dark GDK (which uses direct x), but I'm running into a major problem: pixel drawing is too slow! I don't know much about directly accessing pixels in memory nor how to control them once they've been accessed, so I searched the internet and found this code:
Drawing one pixel at the time is time-consuming. You should try to draw an array of pixels at once:
This just needs reordering (I assume that you don't store all the x-, y-coordinates, red-, green-, blue- and alpha-components of the pixels in an array), but you get the idea.
This eliminates the multiple draw-calls, that take most of your time. This function is explained here.
Emiel1
void d3d_dot (int *x1, int *y1, int *r, int *g, int *b, int *a, int count){ TransformedVertex lineList[] = new TransformedVertex[count]; for (unsigned int i = 0; i < count; ++i) { lineList.x = (float)x1; lineList.y = (float)y1; lineList.z = 1.0f; lineList.color = D3DCOLOR_ARGB (a, r, g, b); } g_pd3dDevice->SetTexture(0,NULL); g_pd3dDevice->SetTexture(1,NULL); g_pd3dDevice->SetVertexShader(NULL); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetFVF(D3D_FVF_2D_VERTEX); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); g_pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST,count,lineList,sizeof(TransformedVertex)); delete[] lineList;}
This just needs reordering (I assume that you don't store all the x-, y-coordinates, red-, green-, blue- and alpha-components of the pixels in an array), but you get the idea.
This eliminates the multiple draw-calls, that take most of your time. This function is explained here.
Emiel1
I don't have much experience with directx (can't be that much diferent from opengl) so I don't know all options there are but one I came up with when I was reading your post is:
every frame:
Store the color of every pixel in a buffer in the RAM. Then send that buffer to the GPU as texture and draw a screen aligned quad with that texture.
I think this is a quite lot more complicated but also faster.
If you're using cpp it's better to make a somewhat more OO-design because the example I gave is quite unmanageable at larger scale.
edit:
I think you can beter use the method of emiel1 because mine is a little overkill here.
every frame:
Store the color of every pixel in a buffer in the RAM. Then send that buffer to the GPU as texture and draw a screen aligned quad with that texture.
I think this is a quite lot more complicated but also faster.
struct RGB; // a struct with 3 bytes representing a color.RGB Buffer[100][100]; // the bufferwhile (true) // main loop{ setBlack(Buffer) RGB color = {220, 123, 0} Buffer[22][44] = color; convertToTextureAndSendItToTheGPU(Buffer) // I can't help you with this part.}
If you're using cpp it's better to make a somewhat more OO-design because the example I gave is quite unmanageable at larger scale.
edit:
I think you can beter use the method of emiel1 because mine is a little overkill here.
Thanks to both of you for the quick replies!
Flammable, I have no idea about the "convertToTextureAndSendItToTheGPU(Buffer)", so your idea won't do me any good.
Emiel, I'll try it. I'll have to rework some stuff in my code though, so it might take a while...
EDIT: Ok, that was quicker than expected. I've managed to make some code. Is this as optimised as possible?
EDIT: Wow. I just tested it and it takes 400x400 pixels being updated every second at more than 40 FPS! that's more than 16 times faster than before, but is it fast enough for a sand game with all the physics calculations?
[Edited by - Element of Power on February 14, 2010 9:42:50 AM]
Flammable, I have no idea about the "convertToTextureAndSendItToTheGPU(Buffer)", so your idea won't do me any good.
Emiel, I'll try it. I'll have to rework some stuff in my code though, so it might take a while...
EDIT: Ok, that was quicker than expected. I've managed to make some code. Is this as optimised as possible?
#include "DarkSDK.h"#include "d3d9.h"#define D3D_FVF_2D_VERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)struct TransformedVertex // D3D_FVF_2D_VERTEX{ float x, y, z, w; // Position of vertex in 3D space DWORD color; // Color of vertex};IDirect3DDevice9* g_pd3dDevice = NULL;TransformedVertex g_d3dLineList [0xFFFFFF];int g_d3dCount = 0;void InitD3DFunc() { g_pd3dDevice = dbGetDirect3DDevice();}void d3d_dot (int x1, int y1, int r, int g, int b, int a){ g_d3dLineList[g_d3dCount].x = (float)x1; g_d3dLineList[g_d3dCount].y = (float)y1; g_d3dLineList[g_d3dCount].z = 1.0f; g_d3dLineList[g_d3dCount].color = D3DCOLOR_ARGB (a, r, g, b); g_d3dCount++;}void d3d_drawDots(){ g_pd3dDevice->SetTexture(0,NULL); g_pd3dDevice->SetTexture(1,NULL); g_pd3dDevice->SetVertexShader(NULL); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetFVF(D3D_FVF_2D_VERTEX); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); g_pd3dDevice->DrawPrimitiveUP(D3DPT_POINTLIST,g_d3dCount,g_d3dLineList,sizeof(TransformedVertex)); g_d3dCount = 0;}
EDIT: Wow. I just tested it and it takes 400x400 pixels being updated every second at more than 40 FPS! that's more than 16 times faster than before, but is it fast enough for a sand game with all the physics calculations?
[Edited by - Element of Power on February 14, 2010 9:42:50 AM]
Quote:Original post by Element of PowerIt should be fast enough, as long as you don't have too many pixels on top of each other. This shouldn't happen if you do the physics correctly.
Wow. I just tested it and it takes 400x400 pixels being updated every second at more than 40 FPS! that's more than 16 times faster than before, but is it fast enough for a sand game with all the physics calculations?
Quote:Original post by Element of PowerIt is optimised as far as I know, but using that much global variables isn't good form. Try this to make it more reusable:
Is this as optimised as possible?
void d3d_drawDots(TransformedVertex *dots, int count);
Emiel1
Quote:I just tested it and it takes 400x400 pixels being updated every second at more than 40 FPS!
Do you compile in release mode?
If you're running in debug mode it might be a lot slower than necessary.
I didn't even realise this debug/release mode compile thing existed. Thanks for the tip - I just gained ~ 3 FPS.
EDIT: I just saw Emiel's edit.
[Edited by - Element of Power on February 14, 2010 10:30:29 AM]
EDIT: I just saw Emiel's edit.
Quote:It is optimised as far as I know, but using that much global variables isn't good form. Try this to make it more reusable:It's reusable enough how it is. Anyway, I can't think what I'd ever use this for besides a sand game...
void d3d_drawDots(TransformedVertex *dots, int count);
[Edited by - Element of Power on February 14, 2010 10:30:29 AM]
If every pixel you ever draw is drawn manually from the CPU, then it would probably be faster to create a texture in system memory, lock it and update the pixels, and then send it to the GPU with UpdateTexture.
yeah just use a dynamic texture and lock it
It's very fast.
device->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, format, D3DPOOL_DEFAULT, &tex, NULL);D3DLOCKED_RECT lr;tex->LockRect(0, &lr, NULL, 0);DWORD* bits = (DWORD *)lr.pBits; // here's your pointer to the pixelstex->UnlockRect(0);
It's very fast.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement