xboxscene.org forums

Author Topic: Need Help With D3d9  (Read 96 times)

dstruktiv

  • Archived User
  • Full Member
  • *
  • Posts: 204
Need Help With D3d9
« on: January 21, 2010, 07:24:00 PM »

I hope there's some people that visit here that are familiar with D3D9...

I'm wanting to port some emulators to the 360. Having no idea about how an emulator works I decided to code a basic one from scratch so I could learn the process, at least then I'd have some background knowledge when it comes to porting something a bit more complex.

I decided to start with the Chip 8, some old school 1970's thing that plays shit like pong.

So I have this thing coded and working minus the display. In my debug logs I can see it processing all the opcodes etc - I haven't coded proper input yet (That will be piss easy once I have a display) so for now every time it check for input I just return an up or down key press.

I have a screen buffer for the emulator, it's a char array, 1 = White, 0 = black.

CODE
unsigned char screen[64*32]


Now I need to take this buffer and translate that to D3D9 instructions.

What was suggested to me was to create a texture, then each update lock it, clear it out and individually fill in the pixels depending on what I had in my screen buffer, then unlock it and display it.

Vincent helped me for a few hours and nothing he suggested was working and then he came across this little gem in the sdk docs:

QUOTE
Textures are stored in a device dependent format on the Xbox 360. The Windows trick of locating a pixel by computing row*pitch+col*texelsize does not work because the textures are stored in a tiled format.


QUOTE
The only way to find a pixel is to use the appropriate XGraphics function (XGAddress2DTiledExtent, XGAddress2DTiledOffset, XGAddress2DTiledX, or XGAddress2DTiledY)


Vincent's Xbox has rrod so he can't test things out himself unfortunately.

So forging ahead by myself now I figure I need to use

CODE
XGAddress2DTiledOffset(
         UINT x, //X-coordinate of the block.
         UINT y, //X-coordinate of the block.
         UINT Width, //Pitch of the image, in blocks.
         UINT TexelPitch //Size of an image block, in bytes.
)


Which should return the offset of the specified pixel within the texture. My problem is... I'm useless with this and am ready to murder who ever invented D3D9.

Honestly all I need to do is to figure out how to make a pixel either white or black, I can figure out the code to do either or depending on whats in my screen buffer but for now if someone can just show me how to locate 1 pixel and make it either white or black I would be thrilled!

The closest I've got so far is accidentally making the top half of my rectangle black when I was tyring to make the whole thing white (When it's created it's filled with random data so if I don't odify it then it's just a series of random colours)

Here's my code:

CODE

#include
#include
#include
#include

#include
#include
#include
#include
#include
#include "xfilecache.h"
#include

#include "AtgApp.h"
#include "AtgFont.h"
#include "AtgHelp.h"
#include "AtgInput.h"
#include "AtgResource.h"
#include "AtgSignIn.h"
#include "AtgUtil.h"
#include "AtgSimpleShaders.h"
#include "AtgDebugDraw.h"

using namespace std;

typedef unsigned char u8;
typedef unsigned char byte;
typedef unsigned short u16;

u8 V[16] = {0x0}; // 16 8-bit registers V0 - VF
u16 I = 0x0; // Memory address register
u8 SP = 0x0; // Stack pointer is used to point to the topmost level of the stack.
u16 Stack[16] = {0x0}; // The stack is an array of 16 16-bit values, used to store the address that the interpreter shoud return to when finished with a subroutine
u16 PC = 0x200; // Program counter starting at mem address 0x200 because on the original console the OS took up the first 200 bytes
u8 Memory[0xFFF] = {0x0}; // 4KB of memory
u16 Opcode = 0x0; // Current instruction
byte dtime; // Delay timer
byte stime; // Sound timer
byte keyval; // Key press
byte vx, yline, data, vxval, vyval; // Screen data
byte screen[2049]; // New screen to display
byte old_screen[2049]; // Old screen just displayed
int count = 0;
bool end = false;
bool debugEnabled = true;
IDirect3DTexture9* display;
D3DLOCKED_RECT rect;

void debugLog(char* output)
{
    if (debugEnabled)
    {
        ofstream writeLog;

        writeLog.open("game:\\debug.log",ofstream::app);
        if (writeLog.is_open())
        {
          writeLog.write(output,strlen(output));
          writeLog.write("\n",1);
        }
        writeLog.close();
    }
}

// Controls //
byte check_keys()
{
    byte keyval = 0;

    int xx = rand();

    if (xx > 100)
    {
        keyval = 5;
    }
    else
    {
        keyval = 8;
    }
    return keyval;
}

// CPU //
void cpu(){

    Opcode = ((Memory[PC]<<8) + Memory[PC+1]);
    
    switch (Opcode&0xF000)
    {
        case 0x0000:
            switch(Opcode&0x00FF)
            {
                case 0x00E0:
                    debugLog("00E0\n");
                    for(int i=0; i <2047; i++ ){
                        screen = 0;
                    }
                    PC += 2;
                break;

                case 0x00EE:
                    debugLog("00EE\n");
                    SP -= 1;
                    PC = Stack[SP];
                    PC += 2;
                break;

                case 0X00FF:
                    debugLog("00FF\n");
                    PC+=2;
                break;

                default:
                    debugLog("Opcode not found\n");
                    debugLog((char*)PC);
                    end = true;
                break;  
            }    
        break;

        case 0x1000:
            debugLog("1NNN\n");
            PC = (Opcode&0x0FFF);
        break;

        case 0x2000:
            debugLog("2NNN\n");
            Stack[SP] = PC;
            SP += 1;
            PC = (Opcode&0x0FFF);
        break;

        case 0x3000:
            debugLog("3XNN\n");
            if(V[((Opcode&0x0F00)>>8)] == (Opcode&0x00FF))
            {
                PC += 4;
            }
            else
            {
                PC +=2;
            }
        break;

        case 0x4000:
            debugLog("4XNN\n");
            if(V[((Opcode&0x0F00)>>8)] != (Opcode&0x00FF))
            {
                PC += 4;    
            }
            else
            {
                PC +=2;
            }
        break;

        case 0x5000:
            debugLog("5XY0\n");
            if(V[((Opcode&0x0F00)>>8)] == V[((Opcode&0x00F0)>>4)])
            {
                PC += 4;    
            }
            else
            {
                PC +=2;
            }
        break;

        case 0x6000:
            debugLog("6XNN\n");
            V[((Opcode&0x0F00)>>8)] = (Opcode&0x00FF);
            PC+=2;
        break;

        case 0x7000:
            debugLog("7XNN\n");
             V[((Opcode&0x0F00)>>8)]=(V[((Opcode&0x0F00)>>8)]+(Opcode&0x00FF));
            PC+=2;
        break;

        case 0x8000:
            switch (Opcode&0x000F){

                case 0x0:
                    debugLog("8XY0\n");
                    V[((Opcode&0x0F00)>>8)]=V[((Opcode&0x00F0)>>4)];
                    PC+=2;
                break;

                case 0x1:
                    debugLog("8XY1\n");
                    V[((Opcode&0x0F00)>>8)]=(V[((Opcode&0x0F00)>>8)]|V[((Opcode&0x00F0)>>4)]);
                    PC+=2;
                break;

                case 0x2:
                    debugLog("8XY2\n");
                    V[((Opcode&0x0F00)>>8)]=(V[((Opcode&0x0F00)>>8)]&V[((Opcode&0x00F0)>>4)]);
                    PC+=2;
                break;

                case 0x3:
                    debugLog("8XY3\n");
                    V[((Opcode&0x0F00)>>8)]=(V[((Opcode&0x0F00)>>8)]^V[((Opcode&0x00F0)>>4)]);
                    PC+=2;
                break;

                case 0x4:
                    debugLog("8XY4\n");
                    if((V[((Opcode&0x00F0)>>4)]+V[((Opcode&0x0F00)>>8)]) > 0xFF)
                    {
                        V[0xF] = 0x01;
                    }
                    else
                    {
                        V[0xF] = 0x00;
                    }
                    V[((Opcode&0x0F00)>>8)]+=V[((Opcode&0x00F0)>>4)];
                    PC+=2;
                break;

                case 0x5:
                    debugLog("8XY5\n");
                    if (V[((Opcode&0x00F0)>>4)]>(V[((Opcode&0x0F00)>>8)]))
                    {
                        V[0xF]=00;
                    }
                    else
                    {
                        V[0xF]=1;
                    }
                    V[((Opcode&0x0F00)>>8)]-=V[((Opcode&0x00F0)>>4)];
                    PC+=2;
                break;

                case 0x6:
                    debugLog("8XY6\n");
                    V[0xF]=(V[((Opcode&0x0F00)>>8)]&0x1);
                    V[((Opcode&0x0F00)>>8)]>>=1;
                    PC+=2;
                break;

                case 0x7:
                    debugLog("8XY7\n");
                    if(V[((Opcode&0x00F0)>>4)] < V[((Opcode&0x0F00)>>8)])
                    {
                        V[0xF] = 0x00;
                    }
                    else
                    {
                        V[0xF] = 0x01;
                    }
                    V[((Opcode&0x0F00)>>8)] = V[((Opcode&0x00F0)>>4)] - V[((Opcode&0x0F00)>>8)];
                    PC+=2;
                break;

                case 0xE:
                    debugLog("8XYE\n");
                    V[0xF] = ((V[((Opcode&0x0F00)>>8)]&0x80)>>7);
                    V[((Opcode&0x0F00)>>8)] <<=1;
                    PC+=2;
                break;

                default:
                    debugLog("Opcode not found\n");
                    debugLog((char*)PC);
                    end = true;
                break;

            }
        break;

        case 0x9000:
            debugLog("9XY0\n");
            if (V[((Opcode&0x0F00)>>8)] != V[((Opcode&0x00F0)>>4)])
            {
                PC += 4;
            }
            else
            {
                PC += 2;
            }
        break;

        case 0xA000:
            debugLog("ANNN\n");
            I = (Opcode&0x0FFF);
            PC += 2;
        break;

        case 0xB000:
            debugLog("BNNN\n");
            PC = (Opcode&0x0FFF) + V[0x0];
        break;

        case 0xC000:
            debugLog("CXNN\n");
            V[((Opcode&0x0F00)>>8)] = (rand()&(Opcode&0x00FF));
            PC += 2;
        break;

        case 0xD000:
            debugLog("DXYN\n");
            vxval = V[(Opcode&0x0F00)>>8];
            vyval = V[(Opcode&0x00F0)>>4];

            if ((Opcode&0x000F)==0)
                for(yline=0; yline<16; yline++ ){
                data = Memory[I+yline];
                for(vx=0; vx<16; vx++){
                if((data&(0x80>>vx))!=0){
                    if(screen[ vx + vxval + ((vyval+yline) * 64)] == 1)
                        V[15] = 1;
                        screen[ vx + vxval + ((vyval+yline) * 64)] ^= 1;
                    }
                }
            }
            else{
                for (yline=0;yline<(Opcode&0x000F);yline++){
                    data = (Memory[I+yline]);
                    for(vx=0;vx<8;vx++){
                        if ((data&(0x80>>vx))!=0){
                            if (  screen[ vx + vxval + (( vyval + yline) * 64)]==1)
                            V[15]=1;
                            screen[ vx + vxval + ( (vyval + yline) * 64)]^=1;
                        }
                    }
                }
            }
            PC+=2;
        //    RenderGame( pDevice );
            for(yline=0; yline<32; yline++)
            for(vx=0; vx<64; vx++)
            old_screen[vx + (yline *64)] = screen[vx + (yline *64)];
        break;

        case 0xE000:
            switch (Opcode&0x00FF){
                case 0x9E:
                debugLog("EX9E\n");
                V[((Opcode&0x0F00)>>8)] = check_keys();
                    PC +=2;
                break;

                case 0xA1:
                    debugLog("EXA1\n");
                    V[((Opcode&0x0F00)>>8)] = check_keys();
                    PC +=2;
                break;
            }
        break;

        case 0xF000:
            switch (Opcode&0x00FF){
                case 0x07:
                    debugLog("FX07\n");
                    V[((Opcode&0x0F00)>>8)] = dtime;
                    PC+=2;
                break;

                case 0x0A:
                    debugLog("FX0A\n");
                    keyval=check_keys();
                    V[((Opcode&0x0F00)>>8)]=keyval;
                    PC+=2;
                break;

                case 0x15:
                    debugLog("FX15\n");
                    dtime = V[((Opcode&0x0F00)>>8)];
                    PC+=2;
                break;

                case 0x18:
                    debugLog("FX18\n");
                    stime = V[((Opcode&0x0F00)>>8)];
                    PC+=2;
                break;

                case 0x1E:
                    debugLog("FX1E\n");
                    I += V[((Opcode&0x0F00)>>8)];
                    PC+=2;
                break;

                case 0x29:
                    debugLog("FX29\n");
                     I = (V[((Opcode&0x0F00)>>8)]*5);
                    PC+=2;
                break;

                case 0x30:
                    debugLog("FX30\n");
                    I = (V[((Opcode&0x0F00)>>8)]*10);
                    PC+=2;
                break;

                case 0x33:
                    debugLog("FX33\n");
                    Memory = (V[((Opcode&0x0F00)>>8)]/100);
                    Memory[I+1] = ((V[((Opcode&0x0F00)>>8)]/10)%10);
                    Memory[I+2] = ((V[((Opcode&0x0F00)>>8)]%100)%10);
                    PC+=2;
                break;

                case 0x55:
                    debugLog("FX55\n");
                    for(int i=0; i<=((Opcode&0x0F00)>>8); i++ ){
                        Memory[I+i] = V;
                    }
                    PC+=2;
                break;

                case 0x65:
                    debugLog("FX65\n");
                    for(int i=0; i<=((Opcode&0x0F00)>>8); i++ ){
                        V = Memory[I+i];
                    }
                    PC+=2;
                break;

                default:
                    debugLog("Opcode not found\n");
                    debugLog((char*)PC);
                    end = true;
                break;
            }
        break;

        default:
            debugLog("Opcode not found\n");
            debugLog((char*)PC);
            end = true;
        break;
    }
}

class Sample : public ATG::Application
{
    ATG::Font m_Font;
    DWORD m_dwFirstUserIndex;
    XINPUT_STATE m_InputState;

private:
    virtual HRESULT Initialize();
    virtual HRESULT Update();
    virtual HRESULT Render();
};

void DrawTextureScaled( LPDIRECT3DTEXTURE9 curTexture, int x, int y, int w, int h )
{
    D3DRECT Rect;

    Rect.x1 = x;
    Rect.y1 = y;
    Rect.x2 = x + w;
    Rect.y2 = y + h;

    ATG::DebugDraw::DrawScreenSpaceTexturedRect( Rect, curTexture, 0 );
}

HRESULT Sample::Initialize()
{

    ifstream inFile;
    inFile.open("game:\\pong.ch8",ifstream::binary);
    if(inFile.is_open()){debugLog("pong open");}
    inFile.read((char*)&Memory[0x200],0xFFF);
    inFile.close();

    int x, y;
    for(y=0; y<32; y++)
        for(x=0; x<64; x++)
        {
            old_screen[x + (y *64)] = 0;
            screen[x + (y *64)] = 0;
        }

    if( FAILED( m_Font.Create( "game:\\Media\\Fonts\\Arial_16.xpr" ) ) )
        return ATGAPPERR_MEDIANOTFOUND;

    m_Font.SetWindow( ATG::GetTitleSafeArea() );

    ATG::SimpleShaders::Initialize( NULL, NULL );
    m_pd3dDevice ->CreateTexture(64, 32, 1, 0, D3DFMT_R8G8_B8G8 , D3DPOOL_DEFAULT, &display, 0);
    return S_OK;
}


HRESULT Sample::Update()
{
    display->LockRect(0,&rect,NULL, NULL); ////////////////////////////////////In between lock and unlock is where the magic needs to happen!!!!

        BYTE* pByte =(BYTE*)rect.pBits;
        
        for (BYTE y=0;y<32;++y)
        {
            for (BYTE x=0;x<64;++x)
            {
            
                //pByte[XGAddress2DTiledOffset(x,y,256,4)] = (BYTE)1;
                //pByte[XGAddress2DTiledOffset(x,y,256,4)+1] = (BYTE)1;
                //pByte[XGAddress2DTiledOffset(x,y,256,4)+2] = (BYTE)1;
                //pByte[XGAddress2DTiledOffset(x,y,256,4)+3] = (BYTE)1;

            }
        }

    display->UnlockRect(0);

    cpu();
    if (dtime>0)dtime-=1;
     if (stime>0)stime-=1;

    return S_OK;
}


HRESULT Sample::Render()
{
    ATG::RenderBackground( 0xFFFFFFFF, 0x00000000 );
    DrawTextureScaled(display,20,20,64*10,32*10);
    m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

    return S_OK;
}


VOID __cdecl main()
{
    Sample atgApp;
    ATG::GetVideoSettings( &atgApp.m_d3dpp.BackBufferWidth, &atgApp.m_d3dpp.BackBufferHeight );
    atgApp.Run();
}


This is what I get on screen with the code above (The shit in the rectangle is just due to the random data inside the texture when it's created - I'm not modifying anything as I don't know how:

(IMG:http://i18.photobucket.com/albums/b145/Powerslayer/IMG_2051.jpg)

And here's my debug log so I know that in the background everyhting is processing fine (This is A LOT bigger, I've just taken a bit from the top of it):

CODE

pong open
6XNN

6XNN

6XNN

6XNN

ANNN

DXYN

DXYN

6XNN

2NNN

ANNN

FX33

FX65

FX29

6XNN

6XNN

DXYN

7XNN

FX29

DXYN

00EE
Logged

lantus

  • Archived User
  • Sr. Member
  • *
  • Posts: 297
Need Help With D3d9
« Reply #1 on: January 21, 2010, 08:32:00 PM »

A few things

- the "windows trick" works just fine on the 360. You can create different format textures on the 360, linear ones for example would work in this instance

- you need to consider what format the target texture is. Since chip8 outputs either black or white as its color, its going to be an 8 bit palette. So your render code will need to iterate through each pixel in "screen" (assuming this is your source buffer) and map it to your pBits pointer in your LockRect() call . By map  in mean set the color value in pBits. Keep in mind that if your target texture is 32 bits  you will need to map your color value to a DWORD for example.

- in your code you are setting the pByte values to 1. im assuming you are trying to testby trying to display white pixels on the screen but 1 is not white in this instance.

A 32 bit texture will contain 32 bytes of data for its color value, 8 bytes for alpha channel, 8 for red, 8 for green, 8 for blue. If you want white then this will come to 0xFF 0xFF 0xFF 0xFF. A value of black will be 0x00, 0x00, 0x00, 0x00

hope this helps. feel free to pm me here or on irc
Logged

Sascoo

  • Archived User
  • Newbie
  • *
  • Posts: 18
Need Help With D3d9
« Reply #2 on: January 22, 2010, 04:02:00 PM »

It's been a while since I used d3d9 but I will give it a shot.  The main thing is you are using D3DFMT_R8G8_B8G8 which is a 32 bit texture format you need to use an array of 32, not BYTE

CODE

IDirect3DSurface9 * surface = 0;
display->GetSurfaceLevel(0, &surface);

surface->LockRect(0,&rect,NULL, D3DUSAGE_WRITEONLY); // I am not sure if you need write only but I added it anyway...

int* pInt =(int*)rect.pBits;
        
for (BYTE y=0;y<32;++y)
{
    for (BYTE x=0;x<64;++)
       pInt[y*32+x] = (int)1; // 0xff ... ?
}

surface->UnlockRect();
surface->Release();


This post has been edited by Sascoo: Jan 23 2010, 12:03 AM
Logged

dstruktiv

  • Archived User
  • Full Member
  • *
  • Posts: 204
Need Help With D3d9
« Reply #3 on: January 22, 2010, 04:05:00 PM »

Thank you lantus! That info about the Lin format made everything work (IMG:style_emoticons/default/smile.gif) I have to thank Vincent and Fallen93 though because they put up with me for hours trying to sort it out, just that texture format was the key (IMG:style_emoticons/default/smile.gif)

CODE
m_pd3dDevice ->CreateTexture(64, 32, 1, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_DEFAULT, &display, 0);

        display->LockRect(0,&rect,NULL, NULL);

        BYTE* pByte =(BYTE*)rect.pBits;

        for (DWORD y=0;y<32;++y)
        {
            for (DWORD x=0;x<64;++x)
            {
                DWORD index = (x*4)+(y*rect.Pitch);
                pByte[index]     = (BYTE)(screen[(y*64) + x] == 0 ? 0x00 : 0xFF);
                pByte[index+1]     = (BYTE)(screen[(y*64) + x] == 0 ? 0x00 : 0xFF);
                pByte[index+2]     = (BYTE)(screen[(y*64) + x] == 0 ? 0x00 : 0xFF);
                pByte[index+3]    = (BYTE)(screen[(y*64) + x] == 0 ? 0x00 : 0xFF);
            }
        }

    display->UnlockRect(0);


(IMG:http://i18.photobucket.com/albums/b145/Powerslayer/IMG_2060.jpg)
Logged